Basic assertion validator.
authorScott Cantor <cantor.2@osu.edu>
Wed, 7 Mar 2007 04:25:35 +0000 (04:25 +0000)
committerScott Cantor <cantor.2@osu.edu>
Wed, 7 Mar 2007 04:25:35 +0000 (04:25 +0000)
.cdtproject
saml/Makefile.am
saml/binding/impl/XMLSigningRule.cpp
saml/saml.vcproj
saml/saml1/profile/AssertionValidator.cpp [new file with mode: 0644]
saml/saml1/profile/AssertionValidator.h [new file with mode: 0644]
saml/saml2/profile/AssertionValidator.cpp [new file with mode: 0644]
saml/saml2/profile/AssertionValidator.h [new file with mode: 0644]
saml/signature/SignatureProfileValidator.cpp
saml/signature/SignatureProfileValidator.h

index bef0879..5bc0b69 100644 (file)
@@ -1,9 +1,9 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>\r
+<?xml version="1.0" encoding="UTF-8"?>\r
 <?eclipse-cdt version="2.0"?>\r
 \r
 <cdtproject id="org.eclipse.cdt.make.core.make">\r
-<extension id="org.eclipse.cdt.core.nullindexer" point="org.eclipse.cdt.core.CIndexer"/>\r
 <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>\r
+<extension id="org.eclipse.cdt.core.nullindexer" point="org.eclipse.cdt.core.CIndexer"/>\r
 <data>\r
 <item id="scannerConfiguration">\r
 <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>\r
 <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/" 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/" 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/saml1/binding"/>\r
-<pathentry kind="src" path="saml/saml1/binding/impl"/>\r
 <pathentry excluding="impl/" kind="src" path="saml/saml1/core"/>\r
 <pathentry kind="src" path="saml/saml1/core/impl"/>\r
-<pathentry excluding="impl/" kind="src" path="saml/saml2/binding"/>\r
-<pathentry kind="src" path="saml/saml2/binding/impl"/>\r
+<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 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
+<pathentry kind="src" path="saml/saml2/binding/impl"/>\r
 <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/encryption"/>\r
 <pathentry kind="src" path="saml/signature"/>\r
 <pathentry kind="src" path="saml/util"/>\r
index 8183f96..9a7a5da 100644 (file)
@@ -18,12 +18,16 @@ saml1bindincludedir = $(includedir)/saml/saml1/binding
 
 saml1coreincludedir = $(includedir)/saml/saml1/core
 
+saml1profincludedir = $(includedir)/saml/saml1/profile
+
 saml2bindincludedir = $(includedir)/saml/saml2/binding
 
 saml2coreincludedir = $(includedir)/saml/saml2/core
 
 saml2mdincludedir = $(includedir)/saml/saml2/metadata
 
+saml2profincludedir = $(includedir)/saml/saml2/profile
+
 libsamlinclude_HEADERS = \
        Assertion.h \
        base.h \
@@ -68,6 +72,9 @@ saml1bindinclude_HEADERS = \
        saml1/binding/SAMLArtifactType0002.h \
        saml1/binding/SAML1SOAPClient.h
 
+saml1profinclude_HEADERS = \
+       saml1/profile/AssertionValidator.h
+
 saml2coreinclude_HEADERS = \
        saml2/core/Assertions.h \
        saml2/core/Protocols.h
@@ -88,6 +95,9 @@ saml2mdinclude_HEADERS = \
        saml2/metadata/MetadataProvider.h \
        saml2/metadata/ObservableMetadataProvider.h
 
+saml2profinclude_HEADERS = \
+       saml2/profile/AssertionValidator.h
+
 noinst_HEADERS = \
        internal.h
 
@@ -119,6 +129,7 @@ libsaml_la_SOURCES = \
        saml1/binding/impl/SAML1SOAPEncoder.cpp \
        saml1/binding/impl/SAML1SOAPClient.cpp \
        saml1/binding/impl/SAML1MessageRule.cpp \
+       saml1/profile/AssertionValidator.cpp \
        saml2/core/impl/Assertions20Impl.cpp \
        saml2/core/impl/Assertions20SchemaValidators.cpp \
        saml2/core/impl/Protocols20Impl.cpp \
@@ -146,6 +157,7 @@ libsaml_la_SOURCES = \
        saml2/binding/impl/SAML2SOAPEncoder.cpp \
        saml2/binding/impl/SAML2SOAPClient.cpp \
        saml2/binding/impl/SAML2MessageRule.cpp \
+       saml2/profile/AssertionValidator.cpp \
        encryption/EncryptedKeyResolver.cpp \
        signature/ContentReference.cpp \
        signature/SignatureProfileValidator.cpp \
index ab68b22..fab79bc 100644 (file)
@@ -90,7 +90,7 @@ void XMLSigningRule::evaluate(const XMLObject& message, const GenericRequest* re
     log.debug("validating signature profile");
     try {
         SignatureProfileValidator sigval;
-        sigval.validate(signable->getSignature());
+        sigval.validateSignature(*(signable->getSignature()));
     }
     catch (ValidationException& ve) {
         log.error("signature profile failed to validate: %s", ve.what());
index 107ae93..ec74261 100644 (file)
                                                </File>\r
                                        </Filter>\r
                                </Filter>\r
+                               <Filter\r
+                                       Name="profile"\r
+                                       >\r
+                                       <File\r
+                                               RelativePath=".\saml1\profile\AssertionValidator.cpp"\r
+                                               >\r
+                                       </File>\r
+                               </Filter>\r
                        </Filter>\r
                        <Filter\r
                                Name="signature"\r
                                                </File>\r
                                        </Filter>\r
                                </Filter>\r
+                               <Filter\r
+                                       Name="profile"\r
+                                       >\r
+                                       <File\r
+                                               RelativePath=".\saml2\profile\AssertionValidator.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="Release|Win32"\r
+                                                       >\r
+                                                       <Tool\r
+                                                               Name="VCCLCompilerTool"\r
+                                                               ObjectFile="$(IntDir)\$(InputName)1.obj"\r
+                                                               XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"\r
+                                                       />\r
+                                               </FileConfiguration>\r
+                                       </File>\r
+                               </Filter>\r
                        </Filter>\r
                        <Filter\r
                                Name="encryption"\r
                                                >\r
                                        </File>\r
                                </Filter>\r
+                               <Filter\r
+                                       Name="profile"\r
+                                       >\r
+                                       <File\r
+                                               RelativePath=".\saml1\profile\AssertionValidator.h"\r
+                                               >\r
+                                       </File>\r
+                               </Filter>\r
                        </Filter>\r
                        <Filter\r
                                Name="signature"\r
                                                >\r
                                        </File>\r
                                </Filter>\r
+                               <Filter\r
+                                       Name="profile"\r
+                                       >\r
+                                       <File\r
+                                               RelativePath=".\saml2\profile\AssertionValidator.h"\r
+                                               >\r
+                                       </File>\r
+                               </Filter>\r
                        </Filter>\r
                        <Filter\r
                                Name="encryption"\r
diff --git a/saml/saml1/profile/AssertionValidator.cpp b/saml/saml1/profile/AssertionValidator.cpp
new file mode 100644 (file)
index 0000000..4d3b875
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ *  Copyright 2001-2007 Internet2
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * AssertionValidator.cpp
+ * 
+ * SAML 1.x basic assertion validator
+ */
+
+#include "internal.h"
+#include "saml1/core/Assertions.h"
+#include "saml1/profile/AssertionValidator.h"
+
+#include <log4cpp/Category.hh>
+#include <xmltooling/util/NDC.h>
+
+using namespace opensaml::saml1;
+using namespace xmltooling;
+using namespace log4cpp;
+using namespace std;
+
+void AssertionValidator::validate(const xmltooling::XMLObject* xmlObject) const
+{
+    const Assertion* a=dynamic_cast<const Assertion*>(xmlObject);
+    if (!a)
+        throw ValidationException("Validator only applies to SAML 1.x Assertion objects.");
+    validateAssertion(*a);
+}
+
+void AssertionValidator::validateAssertion(const Assertion& assertion) const
+{
+#ifdef _DEBUG
+    xmltooling::NDC ndc("validate");
+#endif
+
+    const Conditions* conds = assertion.getConditions();
+    // First verify the time conditions, using the specified timestamp, if non-zero.
+    if (m_ts>0 && conds) {
+        unsigned int skew = XMLToolingConfig::getConfig().clock_skew_secs;
+        time_t t=conds->getNotBeforeEpoch();
+        if (m_ts+skew < t)
+            throw ValidationException("Assertion is not yet valid.");
+        t=conds->getNotOnOrAfterEpoch();
+        if (t <= m_ts-skew)
+            throw ValidationException("Assertion is no longer valid.");
+    }
+
+    // Now we process conditions. Only audience restrictions at the moment.
+    const vector<Condition*>& convec = conds->getConditions();
+    for (vector<Condition*>::const_iterator c = convec.begin(); c!=convec.end(); ++c) {
+        if (!validateCondition(*c)) {
+            Category::getInstance(SAML_LOGCAT".AssertionValidator").error("unrecognized Condition in assertion (%s)",
+                (*c)->getSchemaType() ? (*c)->getSchemaType()->toString().c_str() : (*c)->getElementQName().toString().c_str());
+            throw ValidationException("Assertion contains an unrecognized condition.");
+        }
+    }
+}
+
+bool AssertionValidator::validateCondition(const Condition* condition) const
+{
+    const AudienceRestrictionCondition* ac=dynamic_cast<const AudienceRestrictionCondition*>(condition);
+    if (!ac)
+        return false;
+
+    bool found = false;
+    const vector<Audience*>& auds1 = ac->getAudiences();
+    for (vector<Audience*>::const_iterator a = auds1.begin(); !found && a!=auds1.end(); ++a) {
+        for (vector<const XMLCh*>::const_iterator a2 = m_audiences.begin(); !found && a2!=m_audiences.end(); ++a2) {
+            found = XMLString::equals((*a)->getAudienceURI(), *a2);
+        }
+    }
+
+    if (!found) {
+        ostringstream os;
+        os << *ac;
+        Category::getInstance(SAML_LOGCAT".AssertionValidator").error(
+            "unacceptable AudienceRestrictionCondition in assertion (%s)", os.str().c_str()
+            );
+        throw ValidationException("Assertion contains an unacceptable AudienceRestrictionCondition.");
+    }
+
+    return found;
+}
diff --git a/saml/saml1/profile/AssertionValidator.h b/saml/saml1/profile/AssertionValidator.h
new file mode 100644 (file)
index 0000000..68c29c4
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ *  Copyright 2001-2007 Internet2
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file saml/saml1/profile/AssertionValidator.h
+ * 
+ * SAML 1.x basic assertion validator
+ */
+
+#ifndef __saml1_assval_h__
+#define __saml1_assval_h__
+
+#include <saml/base.h>
+#include <xmltooling/validation/Validator.h>
+
+namespace opensaml {
+    namespace saml1 {
+        
+        class SAML_API Assertion;
+        class SAML_API Condition;
+        
+        /**
+         * SAML 1.x basic assertion validator provides time and audience condition checking.
+         */
+        class SAML_API AssertionValidator : public virtual xmltooling::Validator
+        {
+        public:
+            /**
+             * Constructor
+             * 
+             * @param audiences set of audience values representing recipient
+             * @param ts        timestamp to evaluate assertion conditions, or 0 to bypass check
+             */
+            AssertionValidator(const std::vector<const XMLCh*>& audiences, time_t ts=0) : m_ts(ts), m_audiences(audiences) {}
+            virtual ~AssertionValidator() {}
+    
+            void validate(const xmltooling::XMLObject* xmlObject) const;
+
+            /**
+             * Type-safe validation method.
+             * 
+             * @param assertion assertion to validate
+             */
+            virtual void validateAssertion(const Assertion& assertion) const;
+
+            /**
+             * Condition validation.
+             *
+             * <p>Base class version only understands AudienceRestrictionConditions.
+             * 
+             * @param condition condition to validate
+             * @return true iff condition was understood
+             */
+            virtual bool validateCondition(const Condition* condition) const;
+
+        private:
+            time_t m_ts;
+            const std::vector<const XMLCh*>& m_audiences;
+        };
+        
+    };
+};
+
+#endif /* __saml1_assval_h__ */
diff --git a/saml/saml2/profile/AssertionValidator.cpp b/saml/saml2/profile/AssertionValidator.cpp
new file mode 100644 (file)
index 0000000..a7c7eee
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *  Copyright 2001-2007 Internet2
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * AssertionValidator.cpp
+ * 
+ * SAML 2.0 basic assertion validator
+ */
+
+#include "internal.h"
+#include "saml2/core/Assertions.h"
+#include "saml2/profile/AssertionValidator.h"
+
+#include <log4cpp/Category.hh>
+#include <xmltooling/util/NDC.h>
+
+using namespace opensaml::saml2;
+using namespace xmltooling;
+using namespace log4cpp;
+using namespace std;
+
+void AssertionValidator::validate(const xmltooling::XMLObject* xmlObject) const
+{
+    const Assertion* a=dynamic_cast<const Assertion*>(xmlObject);
+    if (!a)
+        throw ValidationException("Validator only applies to SAML 2.0 Assertion objects.");
+    validateAssertion(*a);
+}
+
+void AssertionValidator::validateAssertion(const Assertion& assertion) const
+{
+#ifdef _DEBUG
+    xmltooling::NDC ndc("validate");
+#endif
+
+    const Conditions* conds = assertion.getConditions();
+    // First verify the time conditions, using the specified timestamp, if non-zero.
+    if (m_ts>0 && conds) {
+        unsigned int skew = XMLToolingConfig::getConfig().clock_skew_secs;
+        time_t t=conds->getNotBeforeEpoch();
+        if (m_ts+skew < t)
+            throw ValidationException("Assertion is not yet valid.");
+        t=conds->getNotOnOrAfterEpoch();
+        if (t <= m_ts-skew)
+            throw ValidationException("Assertion is no longer valid.");
+    }
+
+    // Now we process conditions. Only audience restrictions at the moment.
+    const vector<Condition*>& convec = conds->getConditions();
+    for (vector<Condition*>::const_iterator c = convec.begin(); c!=convec.end(); ++c) {
+        if (!validateCondition(*c)) {
+            Category::getInstance(SAML_LOGCAT".AssertionValidator").error("unrecognized Condition in assertion (%s)",
+                (*c)->getSchemaType() ? (*c)->getSchemaType()->toString().c_str() : (*c)->getElementQName().toString().c_str());
+            throw ValidationException("Assertion contains an unrecognized condition.");
+        }
+    }
+}
+
+bool AssertionValidator::validateCondition(const Condition* condition) const
+{
+    const AudienceRestriction* ac=dynamic_cast<const AudienceRestriction*>(condition);
+    if (!ac)
+        return false;
+
+    bool found = false;
+    const vector<Audience*>& auds1 = ac->getAudiences();
+    for (vector<Audience*>::const_iterator a = auds1.begin(); !found && a!=auds1.end(); ++a) {
+        for (vector<const XMLCh*>::const_iterator a2 = m_audiences.begin(); !found && a2!=m_audiences.end(); ++a2) {
+            found = XMLString::equals((*a)->getAudienceURI(), *a2);
+        }
+    }
+
+    if (!found) {
+        ostringstream os;
+        os << *ac;
+        Category::getInstance(SAML_LOGCAT".AssertionValidator").error("unacceptable AudienceRestriction in assertion (%s)", os.str().c_str());
+        throw ValidationException("Assertion contains an unacceptable AudienceRestriction.");
+    }
+
+    return found;
+}
diff --git a/saml/saml2/profile/AssertionValidator.h b/saml/saml2/profile/AssertionValidator.h
new file mode 100644 (file)
index 0000000..0c03284
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ *  Copyright 2001-2007 Internet2
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file saml/saml2/profile/AssertionValidator.h
+ * 
+ * SAML 2.0 basic assertion validator
+ */
+
+#ifndef __saml2_assval_h__
+#define __saml2_assval_h__
+
+#include <saml/base.h>
+#include <xmltooling/validation/Validator.h>
+
+namespace opensaml {
+    namespace saml2 {
+        
+        class SAML_API Assertion;
+        class SAML_API Condition;
+        
+        /**
+         * SAML 2.0 basic assertion validator provides time and audience condition checking.
+         */
+        class SAML_API AssertionValidator : public virtual xmltooling::Validator
+        {
+        public:
+            /**
+             * Constructor
+             * 
+             * @param audiences set of audience values representing recipient
+             * @param ts        timestamp to evaluate assertion conditions, or 0 to bypass check
+             */
+            AssertionValidator(const std::vector<const XMLCh*>& audiences, time_t ts=0) : m_ts(ts), m_audiences(audiences) {}
+            virtual ~AssertionValidator() {}
+    
+            void validate(const xmltooling::XMLObject* xmlObject) const;
+
+            /**
+             * Type-safe validation method.
+             * 
+             * @param assertion assertion to validate
+             */
+            virtual void validateAssertion(const Assertion& assertion) const;
+
+            /**
+             * Condition validation.
+             *
+             * <p>Base class version only understands AudienceRestrictionConditions.
+             * 
+             * @param condition condition to validate
+             * @return true iff condition was understood
+             */
+            virtual bool validateCondition(const Condition* condition) const;
+
+        private:
+            time_t m_ts;
+            const std::vector<const XMLCh*>& m_audiences;
+        };
+        
+    };
+};
+
+#endif /* __saml2_assval_h__ */
index c05ee7e..b748f3b 100644 (file)
@@ -41,11 +41,16 @@ void SignatureProfileValidator::validate(const XMLObject* xmlObject) const
     const Signature* sigObj=dynamic_cast<const Signature*>(xmlObject);
     if (!sigObj)
         throw ValidationException("Validator only applies to Signature objects.");
-    DSIGSignature* sig=sigObj->getXMLSignature();
+    validateSignature(*sigObj);
+}
+
+void SignatureProfileValidator::validateSignature(const Signature& sigObj) const
+{
+    DSIGSignature* sig=sigObj.getXMLSignature();
     if (!sig)
         throw ValidationException("Signature does not exist yet.");
 
-    const SignableObject* signableObj=dynamic_cast<const SignableObject*>(sigObj->getParent());
+    const SignableObject* signableObj=dynamic_cast<const SignableObject*>(sigObj.getParent());
     if (!signableObj)
         throw ValidationException("Signature is not a child of a signable SAML object.");
     
index 5e27452..6e1a8f2 100644 (file)
@@ -39,6 +39,13 @@ namespace opensaml {
         virtual ~SignatureProfileValidator() {}
 
         void validate(const xmltooling::XMLObject* xmlObject) const;
+        
+        /**
+         * Type-safe validation method.
+         *
+         * @param signature Signature to validate
+         */
+        void validateSignature(const xmlsignature::Signature& signature) const;
     };
 
 };