From 1358ecc315370a4dc0c02b941195919ca2bbd4c3 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Sat, 17 Mar 2007 23:46:20 +0000 Subject: [PATCH] SAML 2 SSO validator. --- saml/Makefile.am | 4 +- saml/saml.vcproj | 26 +++++++ saml/saml1/profile/AssertionValidator.h | 10 ++- saml/saml2/profile/AssertionValidator.h | 12 ++-- saml/saml2/profile/BrowserSSOProfileValidator.cpp | 88 +++++++++++++++++++++++ saml/saml2/profile/BrowserSSOProfileValidator.h | 85 ++++++++++++++++++++++ 6 files changed, 217 insertions(+), 8 deletions(-) create mode 100644 saml/saml2/profile/BrowserSSOProfileValidator.cpp create mode 100644 saml/saml2/profile/BrowserSSOProfileValidator.h diff --git a/saml/Makefile.am b/saml/Makefile.am index 3ad4d76..aed243e 100644 --- a/saml/Makefile.am +++ b/saml/Makefile.am @@ -96,7 +96,8 @@ saml2mdinclude_HEADERS = \ saml2/metadata/ObservableMetadataProvider.h saml2profinclude_HEADERS = \ - saml2/profile/AssertionValidator.h + saml2/profile/AssertionValidator.h \ + saml2/profile/BrowserSSOProfileValidator.h noinst_HEADERS = \ internal.h @@ -158,6 +159,7 @@ libsaml_la_SOURCES = \ saml2/binding/impl/SAML2SOAPClient.cpp \ saml2/binding/impl/SAML2MessageRule.cpp \ saml2/profile/AssertionValidator.cpp \ + saml2/profile/BrowserSSOProfileValidator.cpp \ encryption/EncryptedKeyResolver.cpp \ signature/ContentReference.cpp \ signature/SignatureProfileValidator.cpp \ diff --git a/saml/saml.vcproj b/saml/saml.vcproj index 200de7a..f601468 100644 --- a/saml/saml.vcproj +++ b/saml/saml.vcproj @@ -497,6 +497,28 @@ /> + + + + + + + + + + & audiences, time_t ts=0) : m_ts(ts), m_audiences(audiences) {} + AssertionValidator(const std::vector& audiences, time_t ts=0) : m_audiences(audiences), m_ts(ts) {} + virtual ~AssertionValidator() {} void validate(const xmltooling::XMLObject* xmlObject) const; @@ -66,9 +67,12 @@ namespace opensaml { */ virtual bool validateCondition(const Condition* condition) const; - private: - time_t m_ts; + protected: + /** Set of audience values representing recipient. */ const std::vector& m_audiences; + + /** Timestamp to evaluate assertion conditions. */ + time_t m_ts; }; }; diff --git a/saml/saml2/profile/AssertionValidator.h b/saml/saml2/profile/AssertionValidator.h index 0c03284..f1276bd 100644 --- a/saml/saml2/profile/AssertionValidator.h +++ b/saml/saml2/profile/AssertionValidator.h @@ -44,7 +44,8 @@ namespace opensaml { * @param audiences set of audience values representing recipient * @param ts timestamp to evaluate assertion conditions, or 0 to bypass check */ - AssertionValidator(const std::vector& audiences, time_t ts=0) : m_ts(ts), m_audiences(audiences) {} + AssertionValidator(const std::vector& audiences, time_t ts=0) : m_audiences(audiences), m_ts(ts) {} + virtual ~AssertionValidator() {} void validate(const xmltooling::XMLObject* xmlObject) const; @@ -59,16 +60,19 @@ namespace opensaml { /** * Condition validation. * - *

Base class version only understands AudienceRestrictionConditions. + *

Base class version only understands AudienceRestrictions. * * @param condition condition to validate * @return true iff condition was understood */ virtual bool validateCondition(const Condition* condition) const; - private: - time_t m_ts; + protected: + /** Set of audience values representing recipient. */ const std::vector& m_audiences; + + /** Timestamp to evaluate assertion conditions. */ + time_t m_ts; }; }; diff --git a/saml/saml2/profile/BrowserSSOProfileValidator.cpp b/saml/saml2/profile/BrowserSSOProfileValidator.cpp new file mode 100644 index 0000000..ef43724 --- /dev/null +++ b/saml/saml2/profile/BrowserSSOProfileValidator.cpp @@ -0,0 +1,88 @@ +/* + * 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. + */ + +/** + * BrowserSSOProfileValidator.cpp + * + * SAML 2.0 Browser SSO Profile Assertion Validator + */ + +#include "internal.h" +#include "saml2/core/Assertions.h" +#include "binding/HTTPRequest.h" +#include "saml2/profile/BrowserSSOProfileValidator.h" + +#include +#include + +using namespace opensaml::saml2; +using namespace xmltooling; +using namespace log4cpp; +using namespace std; + +void BrowserSSOProfileValidator::validateAssertion(const Assertion& assertion) const +{ +#ifdef _DEBUG + xmltooling::NDC ndc("validate"); +#endif + Category& log = Category::getInstance(SAML_LOGCAT".AssertionValidator"); + + // The assertion MUST have proper confirmation requirements. + const Subject* subject = assertion.getSubject(); + if (subject) { + const vector& confs = subject->getSubjectConfirmations(); + for (vector::const_iterator sc = confs.begin(); sc!=confs.end(); ++sc) { + if (XMLString::equals((*sc)->getMethod(), SubjectConfirmation::BEARER)) { + const SubjectConfirmationDataType* data = dynamic_cast((*sc)->getSubjectConfirmationData()); + + if (m_destination) { + if (!XMLString::equals(m_destination, data ? data->getRecipient() : NULL)) { + log.error("bearer confirmation failed with recipient mismatch"); + continue; + } + } + + if (m_requestID) { + if (!XMLString::equals(m_requestID, data ? data->getInResponseTo() : NULL)) { + log.error("bearer confirmation failed with request correlation mismatch"); + continue; + } + } + + if (m_ts) { + if (!data || !data->getNotOnOrAfter()) { + log.error("bearer confirmation missing NotOnOrAfter attribute"); + continue; + } + else if (data->getNotOnOrAfterEpoch() <= m_ts - XMLToolingConfig::getConfig().clock_skew_secs) { + log.error("bearer confirmation has expired"); + continue; + } + } + + // Save off client address. + if (data) { + auto_ptr_char ip(data->getAddress()); + if (ip.get()) + m_address = ip.get(); + } + + // Pass up for additional checking. + AssertionValidator::validateAssertion(assertion); + } + } + } +} diff --git a/saml/saml2/profile/BrowserSSOProfileValidator.h b/saml/saml2/profile/BrowserSSOProfileValidator.h new file mode 100644 index 0000000..1a8a0c3 --- /dev/null +++ b/saml/saml2/profile/BrowserSSOProfileValidator.h @@ -0,0 +1,85 @@ +/* + * 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/BrowserSSOProfileValidator.h + * + * SAML 2.0 Browser SSO Profile Assertion Validator + */ + +#ifndef __saml2_ssoval_h__ +#define __saml2_ssoval_h__ + +#include + +namespace opensaml { + + namespace saml2 { + + /** + * SAML 2.0 Browser SSO Profile Assertion Validator + * + *

In addition to standard core requirements for validity, SSO assertions + * MUST have NotBefore/NotOnOrAfter attributes and each subject statement + * MUST be confirmable via bearer method. + */ + class SAML_API BrowserSSOProfileValidator : public AssertionValidator + { + public: + /** + * Constructor + * + * @param audiences set of audience values representing recipient + * @param ts timestamp to evaluate assertion conditions, or 0 to bypass check + * @param destination server location to which assertion was delivered, or 0 to bypass check + * @param requestID ID of request that resulted in assertion, or NULL if unsolicited + */ + BrowserSSOProfileValidator( + const std::vector& audiences, + time_t ts=0, + const XMLCh* destination=NULL, + const XMLCh* requestID=NULL + ) : AssertionValidator(audiences, ts), m_destination(destination), m_requestID(requestID) { + } + virtual ~BrowserSSOProfileValidator() {} + + void validateAssertion(const Assertion& assertion) const; + + /** + * Return address information from the confirmed bearer SubjectConfirmation, if any. + * + * @return address information + */ + const char* getAddress() const { + return m_address.c_str(); + } + + protected: + /** Server location to which assertion was delivered. */ + const XMLCh* m_destination; + + /** ID of request that resulted in assertions. */ + const XMLCh* m_requestID; + + private: + /** Address in confirmed bearer SubjectConfirmationData. */ + mutable std::string m_address; + }; + + }; +}; + +#endif /* __saml2_ssoval_h__ */ -- 2.1.4