saml2/profile/impl/Assertion20Validator.cpp \
saml2/profile/impl/BrowserSSOProfile20Validator.cpp \
saml2/profile/impl/BearerConfirmationRule.cpp \
+ saml2/profile/impl/DelegationRestrictionRule.cpp \
saml2/profile/impl/SAML2AssertionPolicy.cpp \
encryption/EncryptedKeyResolver.cpp \
signature/ContentReference.cpp \
/**
* Evaluates the rule against the given request and message.
*
- * <p>An exception will be raised if the message is invalid according to
+ * <p>An exception will be raised if the message is fatally invalid according to
* a policy rule.
*
* <p>The return value is used to indicate whether a message was ignored or
* successfully processed. A false value signals that the rule wasn't successful
- * but was also not unsuccessful, because the rule was inapplicable to the message.
+ * because the rule was inapplicable to the message, but allows other rules to
+ * return an alternate result.
*
* @param message the incoming message
* @param request the protocol request
#define AUDIENCE_POLICY_RULE "Audience"
/**
+ * SecurityPolicyRule for evaluation of SAML DelegationRestriction Conditions.
+ */
+ #define DELEGATION_POLICY_RULE "Delegation"
+
+ /**
* SecurityPolicyRule for TLS client certificate authentication.
*
* Evaluates client certificates against the issuer's metadata.
namespace saml2 {
SAML_DLLLOCAL PluginManager<SecurityPolicyRule,string,const DOMElement*>::Factory BearerConfirmationRuleFactory;
+ SAML_DLLLOCAL PluginManager<SecurityPolicyRule,string,const DOMElement*>::Factory DelegationRestrictionRuleFactory;
}
};
conf.SecurityPolicyRuleManager.registerFactory(XMLSIGNING_POLICY_RULE, XMLSigningRuleFactory);
conf.SecurityPolicyRuleManager.registerFactory(SAML1BROWSERSSO_POLICY_RULE, saml1::BrowserSSORuleFactory);
conf.SecurityPolicyRuleManager.registerFactory(BEARER_POLICY_RULE, saml2::BearerConfirmationRuleFactory);
+ conf.SecurityPolicyRuleManager.registerFactory(DELEGATION_POLICY_RULE, saml2::DelegationRestrictionRuleFactory);
}
SecurityPolicy::IssuerMatchingPolicy SecurityPolicy::m_defaultMatching;
static const XMLCh type[] = UNICODE_LITERAL_4(t,y,p,e);
const char config[] =
- "<PolicyRule type=\"Conditions\" xmlns:saml2=\"urn:oasis:names:tc:SAML:2.0:assertion\" xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\">"\r
- "<PolicyRule type=\"Audience\"/>"\r
- "<PolicyRule type=\"Ignore\">saml:DoNotCacheCondition</PolicyRule>"\r
- "<PolicyRule type=\"Ignore\">saml2:OneTimeUse</PolicyRule>"\r
- "<PolicyRule type=\"Ignore\">saml2:ProxyRestriction</PolicyRule>"\r
- "</PolicyRule>";\r
+ "<PolicyRule type=\"Conditions\" xmlns:saml2=\"urn:oasis:names:tc:SAML:2.0:assertion\" xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\">"
+ "<PolicyRule type=\"Audience\"/>"
+ "<PolicyRule type=\"Ignore\">saml:DoNotCacheCondition</PolicyRule>"
+ "<PolicyRule type=\"Ignore\">saml2:OneTimeUse</PolicyRule>"
+ "<PolicyRule type=\"Ignore\">saml2:ProxyRestriction</PolicyRule>"
+ "</PolicyRule>";
};
ConditionsRule::ConditionsRule(const DOMElement* e) : m_doc(NULL)
bool valid;
const vector<saml2::AudienceRestriction*>& acvec = conds->getAudienceRestrictions();
- for (vector<saml2::AudienceRestriction*>::const_iterator ac = acvec.begin(); ac!=acvec.end(); ++ac) {
+ for (vector<saml2::AudienceRestriction*>::const_iterator ac = acvec.begin(); ac != acvec.end(); ++ac) {
valid = false;
- for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); r != m_rules.end(); ++r) {
- if ((*r)->evaluate(*(*ac), request, policy))
- valid = true;
- }
+ for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
+ valid = (*r)->evaluate(*(*ac), request, policy);
if (!valid)
- throw SecurityPolicyException("AudienceRestriction was not understood by policy.");
+ throw SecurityPolicyException("AudienceRestriction condition not successfully validated by policy.");
}
const vector<saml2::OneTimeUse*>& otvec = conds->getOneTimeUses();
for (vector<saml2::OneTimeUse*>::const_iterator ot = otvec.begin(); ot!=otvec.end(); ++ot) {
valid = false;
- for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); r != m_rules.end(); ++r) {
- if ((*r)->evaluate(*(*ot), request, policy))
- valid = true;
- }
+ for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
+ valid = (*r)->evaluate(*(*ot), request, policy);
if (!valid)
- throw SecurityPolicyException("OneTimeUse was not understood by policy.");
+ throw SecurityPolicyException("OneTimeUse condition not successfully validated by policy.");
}
const vector<saml2::ProxyRestriction*> pvec = conds->getProxyRestrictions();
- for (vector<saml2::ProxyRestriction*>::const_iterator p = pvec.begin(); p!=pvec.end(); ++p) {
+ for (vector<saml2::ProxyRestriction*>::const_iterator p = pvec.begin(); p != pvec.end(); ++p) {
valid = false;
- for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); r != m_rules.end(); ++r) {
- if ((*r)->evaluate(*(*p), request, policy))
- valid = true;
- }
+ for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
+ valid = (*r)->evaluate(*(*p), request, policy);
if (!valid)
- throw SecurityPolicyException("ProxyRestriction was not understood by policy.");
+ throw SecurityPolicyException("ProxyRestriction condition not successfully validated by policy.");
}
const vector<saml2::Condition*>& convec = conds->getConditions();
- for (vector<saml2::Condition*>::const_iterator c = convec.begin(); c!=convec.end(); ++c) {
+ for (vector<saml2::Condition*>::const_iterator c = convec.begin(); c != convec.end(); ++c) {
valid = false;
- for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); r != m_rules.end(); ++r) {
- if ((*r)->evaluate(*(*c), request, policy))
- valid = true;
+ for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
+ valid = (*r)->evaluate(*(*c), request, policy);
+ if (!valid) {
+ throw SecurityPolicyException(
+ "Extension condition ($1) not successfully validated by policy.",
+ params(1,((*c)->getSchemaType() ? (*c)->getSchemaType()->toString().c_str() : "Unknown Type"))
+ );
}
- if (!valid)
- throw SecurityPolicyException("Condition ($1) was not understood by policy.", params(1,(*c)->getElementQName().toString().c_str()));
}
return true;
bool valid;
const vector<saml1::AudienceRestrictionCondition*>& acvec = conds->getAudienceRestrictionConditions();
- for (vector<saml1::AudienceRestrictionCondition*>::const_iterator ac = acvec.begin(); ac!=acvec.end(); ++ac) {
+ for (vector<saml1::AudienceRestrictionCondition*>::const_iterator ac = acvec.begin(); ac != acvec.end(); ++ac) {
valid = false;
- for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); r != m_rules.end(); ++r) {
- if ((*r)->evaluate(*(*ac), request, policy))
- valid = true;
- }
+ for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
+ valid = (*r)->evaluate(*(*ac), request, policy);
if (!valid)
- throw SecurityPolicyException("AudienceRestrictionCondition was not understood by policy.");
+ throw SecurityPolicyException("AudienceRestrictionCondition not successfully validated by policy.");
}
const vector<saml1::DoNotCacheCondition*>& dncvec = conds->getDoNotCacheConditions();
- for (vector<saml1::DoNotCacheCondition*>::const_iterator dnc = dncvec.begin(); dnc!=dncvec.end(); ++dnc) {
+ for (vector<saml1::DoNotCacheCondition*>::const_iterator dnc = dncvec.begin(); dnc != dncvec.end(); ++dnc) {
valid = false;
- for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); r != m_rules.end(); ++r) {
- if ((*r)->evaluate(*(*dnc), request, policy))
- valid = true;
- }
+ for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
+ valid = (*r)->evaluate(*(*dnc), request, policy);
if (!valid)
- throw SecurityPolicyException("DoNotCacheCondition was not understood by policy.");
+ throw SecurityPolicyException("DoNotCacheCondition not successfully validated by policy.");
}
const vector<saml1::Condition*>& convec = conds->getConditions();
- for (vector<saml1::Condition*>::const_iterator c = convec.begin(); c!=convec.end(); ++c) {
+ for (vector<saml1::Condition*>::const_iterator c = convec.begin(); c != convec.end(); ++c) {
valid = false;
- for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); r != m_rules.end(); ++r) {
- if ((*r)->evaluate(*(*c), request, policy))
- valid = true;
+ for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
+ valid = (*r)->evaluate(*(*c), request, policy);
+ if (!valid) {
+ throw SecurityPolicyException(
+ "Extension condition ($1) not successfully validated by policy.",
+ params(1,((*c)->getSchemaType() ? (*c)->getSchemaType()->toString().c_str() : (*c)->getElementQName().toString().c_str()))
+ );
}
- if (!valid)
- throw SecurityPolicyException("Condition ($1) was not understood by policy.", params(1,(*c)->getElementQName().toString().c_str()));
}
return true;
>\r
</File>\r
<File\r
+ RelativePath=".\saml2\profile\impl\DelegationRestrictionRule.cpp"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\saml2\profile\impl\SAML2AssertionPolicy.cpp"\r
>\r
</File>\r
const XMLCh Delegate::CONFIRMATIONMETHOD_ATTRIB_NAME[] = UNICODE_LITERAL_18(C,o,n,f,i,r,m,a,t,i,o,n,M,e,t,h,o,d);
const XMLCh Delegate::DELEGATIONINSTANT_ATTRIB_NAME[] = UNICODE_LITERAL_17(D,e,l,e,g,a,t,i,o,n,I,n,s,t,a,n,t);
const XMLCh DelegationRestrictionType::LOCAL_NAME[] = UNICODE_LITERAL_9(C,o,n,d,i,t,i,o,n);
-const XMLCh DelegationRestrictionType::TYPE_NAME[] =UNICODE_LITERAL_21(D,e,l,e,g,a,t,i,o,n,R,e,s,t,r,i,c,t,i,o,n);
+const XMLCh DelegationRestrictionType::TYPE_NAME[] =UNICODE_LITERAL_25(D,e,l,e,g,a,t,i,o,n,R,e,s,t,r,i,c,t,i,o,n,T,y,p,e);
const XMLCh EncryptedAssertion::LOCAL_NAME[] = UNICODE_LITERAL_18(E,n,c,r,y,p,t,e,d,A,s,s,e,r,t,i,o,n);
const XMLCh EncryptedAttribute::LOCAL_NAME[] = UNICODE_LITERAL_18(E,n,c,r,y,p,t,e,d,A,t,t,r,i,b,u,t,e);
const XMLCh EncryptedElementType::LOCAL_NAME[] = {chNull};
/*
-* Copyright 2001-2007 Internet2
+* Copyright 2001-2009 Internet2
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
--- /dev/null
+/*
+ * 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.
+ */
+
+/**
+ * DelegationRestrictionRule.cpp
+ *
+ * SAML DelegationRestriction SecurityPolicyRule
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "binding/SecurityPolicyRule.h"
+#include "saml2/core/Assertions.h"
+#include "util/SAMLConstants.h"
+
+#include <xmltooling/logging.h>
+
+using namespace opensaml::saml2;
+using namespace opensaml;
+using namespace xmltooling::logging;
+using namespace xmltooling;
+using namespace std;
+
+namespace opensaml {
+ namespace saml2 {
+ class SAML_DLLLOCAL DelegationRestrictionRule : public SecurityPolicyRule
+ {
+ public:
+ DelegationRestrictionRule(const DOMElement* e);
+
+ virtual ~DelegationRestrictionRule() {
+ for_each(m_delegates.begin(), m_delegates.end(), xmltooling::cleanup<Delegate>());
+ }
+ const char* getType() const {
+ return DELEGATION_POLICY_RULE;
+ }
+ bool evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const;
+
+ private:
+ vector<Delegate*> m_delegates;
+ enum {
+ MATCH_ANY,
+ MATCH_NEWEST,
+ MATCH_OLDEST
+ } m_match;
+ };
+
+ SecurityPolicyRule* SAML_DLLLOCAL DelegationRestrictionRuleFactory(const DOMElement* const & e)
+ {
+ return new DelegationRestrictionRule(e);
+ }
+
+ class SAML_DLLLOCAL _isSameDelegate : public binary_function<const Delegate*,const Delegate*,bool>,
+ public unary_function<const Delegate*,bool>
+ {
+ const Delegate* m_operand;
+ bool isSameFormat(const XMLCh* f1, const XMLCh* f2) const {
+ if (!f1 || !*f1)
+ f1 = NameIDType::UNSPECIFIED;
+ if (!f2 || !*f2)
+ f2 = NameIDType::UNSPECIFIED;
+ return XMLString::equals(f1, f2);
+ }
+ bool matches(const NameID* n1, const NameID* n2) const {
+ return (isSameFormat(n1->getFormat(), n2->getFormat()) &&
+ XMLString::equals(n1->getName(), n2->getName()) &&
+ XMLString::equals(n1->getNameQualifier(), n2->getNameQualifier()) &&
+ XMLString::equals(n1->getSPNameQualifier(), n2->getSPNameQualifier()));
+ }
+ public:
+ _isSameDelegate() : m_operand(NULL) {}
+ _isSameDelegate(const Delegate* d) : m_operand(d) {}
+
+ // d1 is the input from the message, d2 is from the policy
+ bool operator()(const Delegate* d1, const Delegate* d2) const {
+ if (!d1->getNameID()) {
+ Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.DelegationRestriction").error(
+ "rule doesn't support evaluation of BaseID or EncryptedID in a Delegate"
+ );
+ return false;
+ }
+ if (!d2->getConfirmationMethod() || XMLString::equals(d1->getConfirmationMethod(), d2->getConfirmationMethod())) {
+ return matches(d1->getNameID(), d2->getNameID());
+ }
+ return false;
+ }
+
+ // d is from the policy
+ bool operator()(const Delegate* d) const {
+ return this->operator()(m_operand, d);
+ }
+ };
+
+ static XMLCh match[] = UNICODE_LITERAL_5(m,a,t,c,h);
+ static XMLCh any[] = UNICODE_LITERAL_8(a,n,y,O,r,d,e,r);
+ static XMLCh newest[] = UNICODE_LITERAL_6(n,e,w,e,s,t);
+ static XMLCh oldest[] = UNICODE_LITERAL_6(o,l,d,e,s,t);
+
+ }
+};
+
+DelegationRestrictionRule::DelegationRestrictionRule(const DOMElement* e) : m_match(MATCH_ANY)
+{
+ if (e) {
+ const XMLCh* m = e->getAttributeNS(NULL, match);
+ if (XMLString::equals(m, newest))
+ m_match = MATCH_NEWEST;
+ else if (XMLString::equals(m, oldest))
+ m_match = MATCH_OLDEST;
+ else if (m && *m && !XMLString::equals(m, any))
+ throw SecurityPolicyException("Invalid value for \"match\" attribute in Delegation rule.");
+
+ try {
+ DOMElement* d = XMLHelper::getFirstChildElement(e, samlconstants::SAML20_DELEGATION_CONDITION_NS, Delegate::LOCAL_NAME);
+ while (d) {
+ auto_ptr<XMLObject> wrapper(XMLObjectBuilder::buildOneFromElement(d));
+ Delegate* down = dynamic_cast<Delegate*>(wrapper.get());
+ if (down) {
+ m_delegates.push_back(down);
+ wrapper.release();
+ }
+ d = XMLHelper::getNextSiblingElement(d, samlconstants::SAML20_DELEGATION_CONDITION_NS, Delegate::LOCAL_NAME);
+ }
+ }
+ catch (exception&) {
+ for_each(m_delegates.begin(), m_delegates.end(), xmltooling::cleanup<Delegate>());
+ throw;
+ }
+ }
+}
+
+bool DelegationRestrictionRule::evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const
+{
+ const DelegationRestrictionType* drt=dynamic_cast<const DelegationRestrictionType*>(&message);
+ if (!drt)
+ return false;
+
+ // If we have no embedded Delegates, the condition evaluates to true.
+ if (m_delegates.empty())
+ return true;
+
+ const vector<Delegate*>& dels = drt->getDelegates();
+ if (m_match == MATCH_ANY) {
+ // Each Delegate in the condition MUST match an embedded Delegate.
+ for (vector<Delegate*>::const_iterator d1 = dels.begin(); d1 != dels.end(); ++d1) {
+ if (find_if(m_delegates.begin(), m_delegates.end(), _isSameDelegate(*d1)) == m_delegates.end())
+ return false;
+ }
+ }
+ else if (m_match == MATCH_OLDEST) {
+ return (search(dels.begin(), dels.end(), m_delegates.begin(), m_delegates.end(), _isSameDelegate()) == dels.begin());
+ }
+ else if (m_match == MATCH_NEWEST) {
+ return (search(dels.rbegin(), dels.rend(), m_delegates.begin(), m_delegates.end(), _isSameDelegate()) == dels.rbegin());
+ }
+
+ return true;
+}
const XMLCh samlconstants::SAML20_DELEGATION_CONDITION_NS[] = // urn:oasis:names:tc:SAML:2.0:conditions:delegation
{ chLatin_u, chLatin_r, chLatin_n, chColon, chLatin_o, chLatin_a, chLatin_s, chLatin_i, chLatin_s, chColon,
chLatin_n, chLatin_a, chLatin_m, chLatin_e, chLatin_s, chColon, chLatin_t, chLatin_c, chColon,
- chLatin_S, chLatin_A, chLatin_M, chLatin_L, chColon, chDigit_2, chDigit_0, chColon,
+ chLatin_S, chLatin_A, chLatin_M, chLatin_L, chColon, chDigit_2, chPeriod, chDigit_0, chColon,
chLatin_c, chLatin_o, chLatin_n, chLatin_d, chLatin_i, chLatin_t, chLatin_i, chLatin_o, chLatin_n, chLatin_s, chColon,
chLatin_d, chLatin_e, chLatin_l, chLatin_e, chLatin_g, chLatin_a, chLatin_t, chLatin_i, chLatin_o, chLatin_n, chNull
};