2 * Licensed to the University Corporation for Advanced Internet
3 * Development, Inc. (UCAID) under one or more contributor license
4 * agreements. See the NOTICE file distributed with this work for
5 * additional information regarding copyright ownership.
7 * UCAID licenses this file to you under the Apache License,
8 * Version 2.0 (the "License"); you may not use this file except
9 * in compliance with the License. You may obtain a copy of the
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17 * either express or implied. See the License for the specific
18 * language governing permissions and limitations under the License.
24 * SAML Conditions SecurityPolicyRule.
28 #include "exceptions.h"
29 #include "binding/SecurityPolicy.h"
30 #include "binding/SecurityPolicyRule.h"
31 #include "saml1/core/Assertions.h"
32 #include "saml2/core/Assertions.h"
34 #include <boost/ptr_container/ptr_vector.hpp>
35 #include <xercesc/util/XMLUniDefs.hpp>
36 #include <xmltooling/logging.h>
37 #include <xmltooling/XMLToolingConfig.h>
38 #include <xmltooling/util/ParserPool.h>
40 using namespace opensaml;
41 using namespace xmltooling::logging;
42 using namespace xmltooling;
43 using namespace boost;
47 class SAML_DLLLOCAL ConditionsRule : public SecurityPolicyRule
50 ConditionsRule(const DOMElement* e);
52 virtual ~ConditionsRule() {
56 const char* getType() const {
57 return CONDITIONS_POLICY_RULE;
59 bool evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const;
63 ptr_vector<SecurityPolicyRule> m_rules;
66 SecurityPolicyRule* SAML_DLLLOCAL ConditionsRuleFactory(const DOMElement* const & e)
68 return new ConditionsRule(e);
71 static const XMLCh Rule[] = UNICODE_LITERAL_10(P,o,l,i,c,y,R,u,l,e);
72 static const XMLCh type[] = UNICODE_LITERAL_4(t,y,p,e);
75 "<PolicyRule type=\"Conditions\" xmlns:saml2=\"urn:oasis:names:tc:SAML:2.0:assertion\" xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\">"
76 "<PolicyRule type=\"Audience\"/>"
77 "<PolicyRule type=\"Ignore\">saml:DoNotCacheCondition</PolicyRule>"
78 "<PolicyRule type=\"Ignore\">saml2:OneTimeUse</PolicyRule>"
79 "<PolicyRule type=\"Ignore\">saml2:ProxyRestriction</PolicyRule>"
83 ConditionsRule::ConditionsRule(const DOMElement* e) : m_doc(nullptr)
85 Category& log=Category::getInstance(SAML_LOGCAT ".SecurityPolicyRule.Conditions");
87 if (!e || !e->hasChildNodes()) {
88 // Default the configuration.
89 istringstream in(config);
90 m_doc = XMLToolingConfig::getConfig().getParser().parse(in);
91 e = m_doc->getDocumentElement();
94 e = XMLHelper::getFirstChildElement(e, Rule);
96 string t = XMLHelper::getAttrString(e, nullptr, type);
99 log.info("building SecurityPolicyRule of type %s", t.c_str());
100 m_rules.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(t.c_str(), e));
102 catch (std::exception& ex) {
103 log.crit("error building SecurityPolicyRule: %s", ex.what());
106 e = XMLHelper::getNextSiblingElement(e, Rule);
110 bool ConditionsRule::evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const
112 const saml2::Assertion* a2=dynamic_cast<const saml2::Assertion*>(&message);
114 const saml2::Conditions* conds = a2->getConditions();
118 // First verify the time conditions, using the specified timestamp.
119 time_t now = policy.getTime();
120 unsigned int skew = XMLToolingConfig::getConfig().clock_skew_secs;
121 time_t t = conds->getNotBeforeEpoch();
123 throw SecurityPolicyException("Assertion is not yet valid.");
124 t = conds->getNotOnOrAfterEpoch();
126 throw SecurityPolicyException("Assertion is no longer valid.");
128 // Now we process conditions, starting with the known types and then extensions.
132 const vector<saml2::AudienceRestriction*>& acvec = conds->getAudienceRestrictions();
133 for (vector<saml2::AudienceRestriction*>::const_iterator ac = acvec.begin(); ac != acvec.end(); ++ac) {
135 for (ptr_vector<SecurityPolicyRule>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
136 valid = r->evaluate(*(*ac), request, policy);
138 throw SecurityPolicyException("AudienceRestriction condition not successfully validated by policy.");
141 const vector<saml2::OneTimeUse*>& otvec = conds->getOneTimeUses();
142 for (vector<saml2::OneTimeUse*>::const_iterator ot = otvec.begin(); ot!=otvec.end(); ++ot) {
144 for (ptr_vector<SecurityPolicyRule>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
145 valid = r->evaluate(*(*ot), request, policy);
147 throw SecurityPolicyException("OneTimeUse condition not successfully validated by policy.");
150 const vector<saml2::ProxyRestriction*> pvec = conds->getProxyRestrictions();
151 for (vector<saml2::ProxyRestriction*>::const_iterator p = pvec.begin(); p != pvec.end(); ++p) {
153 for (ptr_vector<SecurityPolicyRule>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
154 valid = r->evaluate(*(*p), request, policy);
156 throw SecurityPolicyException("ProxyRestriction condition not successfully validated by policy.");
159 const vector<saml2::Condition*>& convec = conds->getConditions();
160 for (vector<saml2::Condition*>::const_iterator c = convec.begin(); c != convec.end(); ++c) {
162 for (ptr_vector<SecurityPolicyRule>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
163 valid = r->evaluate(*(*c), request, policy);
165 throw SecurityPolicyException(
166 "Extension condition ($1) not successfully validated by policy.",
167 params(1,((*c)->getSchemaType() ? (*c)->getSchemaType()->toString().c_str() : "Unknown Type"))
175 const saml1::Assertion* a1=dynamic_cast<const saml1::Assertion*>(&message);
177 const saml1::Conditions* conds = a1->getConditions();
181 // First verify the time conditions, using the specified timestamp.
182 time_t now = policy.getTime();
183 unsigned int skew = XMLToolingConfig::getConfig().clock_skew_secs;
184 time_t t = conds->getNotBeforeEpoch();
186 throw SecurityPolicyException("Assertion is not yet valid.");
187 t = conds->getNotOnOrAfterEpoch();
189 throw SecurityPolicyException("Assertion is no longer valid.");
191 // Now we process conditions, starting with the known types and then extensions.
195 const vector<saml1::AudienceRestrictionCondition*>& acvec = conds->getAudienceRestrictionConditions();
196 for (vector<saml1::AudienceRestrictionCondition*>::const_iterator ac = acvec.begin(); ac != acvec.end(); ++ac) {
198 for (ptr_vector<SecurityPolicyRule>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
199 valid = r->evaluate(*(*ac), request, policy);
201 throw SecurityPolicyException("AudienceRestrictionCondition not successfully validated by policy.");
204 const vector<saml1::DoNotCacheCondition*>& dncvec = conds->getDoNotCacheConditions();
205 for (vector<saml1::DoNotCacheCondition*>::const_iterator dnc = dncvec.begin(); dnc != dncvec.end(); ++dnc) {
207 for (ptr_vector<SecurityPolicyRule>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
208 valid = r->evaluate(*(*dnc), request, policy);
210 throw SecurityPolicyException("DoNotCacheCondition not successfully validated by policy.");
213 const vector<saml1::Condition*>& convec = conds->getConditions();
214 for (vector<saml1::Condition*>::const_iterator c = convec.begin(); c != convec.end(); ++c) {
216 for (ptr_vector<SecurityPolicyRule>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
217 valid = r->evaluate(*(*c), request, policy);
219 throw SecurityPolicyException(
220 "Extension condition ($1) not successfully validated by policy.",
221 params(1,((*c)->getSchemaType() ? (*c)->getSchemaType()->toString().c_str() : (*c)->getElementQName().toString().c_str()))