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 <xercesc/util/XMLUniDefs.hpp>
35 #include <xmltooling/logging.h>
36 #include <xmltooling/XMLToolingConfig.h>
37 #include <xmltooling/util/ParserPool.h>
39 using namespace opensaml;
40 using namespace xmltooling::logging;
41 using namespace xmltooling;
45 class SAML_DLLLOCAL ConditionsRule : public SecurityPolicyRule
48 ConditionsRule(const DOMElement* e);
50 virtual ~ConditionsRule() {
51 for_each(m_rules.begin(), m_rules.end(), xmltooling::cleanup<SecurityPolicyRule>());
55 const char* getType() const {
56 return CONDITIONS_POLICY_RULE;
58 bool evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const;
62 vector<SecurityPolicyRule*> m_rules;
65 SecurityPolicyRule* SAML_DLLLOCAL ConditionsRuleFactory(const DOMElement* const & e)
67 return new ConditionsRule(e);
70 static const XMLCh Rule[] = UNICODE_LITERAL_10(P,o,l,i,c,y,R,u,l,e);
71 static const XMLCh type[] = UNICODE_LITERAL_4(t,y,p,e);
74 "<PolicyRule type=\"Conditions\" xmlns:saml2=\"urn:oasis:names:tc:SAML:2.0:assertion\" xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\">"
75 "<PolicyRule type=\"Audience\"/>"
76 "<PolicyRule type=\"Ignore\">saml:DoNotCacheCondition</PolicyRule>"
77 "<PolicyRule type=\"Ignore\">saml2:OneTimeUse</PolicyRule>"
78 "<PolicyRule type=\"Ignore\">saml2:ProxyRestriction</PolicyRule>"
82 ConditionsRule::ConditionsRule(const DOMElement* e) : m_doc(nullptr)
84 Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.Conditions");
86 if (!e || !e->hasChildNodes()) {
87 // Default the configuration.
88 istringstream in(config);
89 m_doc = XMLToolingConfig::getConfig().getParser().parse(in);
90 e = m_doc->getDocumentElement();
93 e = XMLHelper::getFirstChildElement(e, Rule);
95 string t = XMLHelper::getAttrString(e, nullptr, type);
98 log.info("building SecurityPolicyRule of type %s", t.c_str());
99 m_rules.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(t.c_str(), e));
101 catch (exception& ex) {
102 log.crit("error building SecurityPolicyRule: %s", ex.what());
105 e = XMLHelper::getNextSiblingElement(e, Rule);
109 bool ConditionsRule::evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const
111 const saml2::Assertion* a2=dynamic_cast<const saml2::Assertion*>(&message);
113 const saml2::Conditions* conds = a2->getConditions();
117 // First verify the time conditions, using the specified timestamp.
118 time_t now = policy.getTime();
119 unsigned int skew = XMLToolingConfig::getConfig().clock_skew_secs;
120 time_t t = conds->getNotBeforeEpoch();
122 throw SecurityPolicyException("Assertion is not yet valid.");
123 t = conds->getNotOnOrAfterEpoch();
125 throw SecurityPolicyException("Assertion is no longer valid.");
127 // Now we process conditions, starting with the known types and then extensions.
131 const vector<saml2::AudienceRestriction*>& acvec = conds->getAudienceRestrictions();
132 for (vector<saml2::AudienceRestriction*>::const_iterator ac = acvec.begin(); ac != acvec.end(); ++ac) {
134 for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
135 valid = (*r)->evaluate(*(*ac), request, policy);
137 throw SecurityPolicyException("AudienceRestriction condition not successfully validated by policy.");
140 const vector<saml2::OneTimeUse*>& otvec = conds->getOneTimeUses();
141 for (vector<saml2::OneTimeUse*>::const_iterator ot = otvec.begin(); ot!=otvec.end(); ++ot) {
143 for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
144 valid = (*r)->evaluate(*(*ot), request, policy);
146 throw SecurityPolicyException("OneTimeUse condition not successfully validated by policy.");
149 const vector<saml2::ProxyRestriction*> pvec = conds->getProxyRestrictions();
150 for (vector<saml2::ProxyRestriction*>::const_iterator p = pvec.begin(); p != pvec.end(); ++p) {
152 for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
153 valid = (*r)->evaluate(*(*p), request, policy);
155 throw SecurityPolicyException("ProxyRestriction condition not successfully validated by policy.");
158 const vector<saml2::Condition*>& convec = conds->getConditions();
159 for (vector<saml2::Condition*>::const_iterator c = convec.begin(); c != convec.end(); ++c) {
161 for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
162 valid = (*r)->evaluate(*(*c), request, policy);
164 throw SecurityPolicyException(
165 "Extension condition ($1) not successfully validated by policy.",
166 params(1,((*c)->getSchemaType() ? (*c)->getSchemaType()->toString().c_str() : "Unknown Type"))
174 const saml1::Assertion* a1=dynamic_cast<const saml1::Assertion*>(&message);
176 const saml1::Conditions* conds = a1->getConditions();
180 // First verify the time conditions, using the specified timestamp.
181 time_t now = policy.getTime();
182 unsigned int skew = XMLToolingConfig::getConfig().clock_skew_secs;
183 time_t t = conds->getNotBeforeEpoch();
185 throw SecurityPolicyException("Assertion is not yet valid.");
186 t = conds->getNotOnOrAfterEpoch();
188 throw SecurityPolicyException("Assertion is no longer valid.");
190 // Now we process conditions, starting with the known types and then extensions.
194 const vector<saml1::AudienceRestrictionCondition*>& acvec = conds->getAudienceRestrictionConditions();
195 for (vector<saml1::AudienceRestrictionCondition*>::const_iterator ac = acvec.begin(); ac != acvec.end(); ++ac) {
197 for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
198 valid = (*r)->evaluate(*(*ac), request, policy);
200 throw SecurityPolicyException("AudienceRestrictionCondition not successfully validated by policy.");
203 const vector<saml1::DoNotCacheCondition*>& dncvec = conds->getDoNotCacheConditions();
204 for (vector<saml1::DoNotCacheCondition*>::const_iterator dnc = dncvec.begin(); dnc != dncvec.end(); ++dnc) {
206 for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
207 valid = (*r)->evaluate(*(*dnc), request, policy);
209 throw SecurityPolicyException("DoNotCacheCondition not successfully validated by policy.");
212 const vector<saml1::Condition*>& convec = conds->getConditions();
213 for (vector<saml1::Condition*>::const_iterator c = convec.begin(); c != convec.end(); ++c) {
215 for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
216 valid = (*r)->evaluate(*(*c), request, policy);
218 throw SecurityPolicyException(
219 "Extension condition ($1) not successfully validated by policy.",
220 params(1,((*c)->getSchemaType() ? (*c)->getSchemaType()->toString().c_str() : (*c)->getElementQName().toString().c_str()))