2 * Copyright 2009-2010 Internet2
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 * SAML Conditions SecurityPolicyRule.
24 #include "exceptions.h"
25 #include "binding/SecurityPolicy.h"
26 #include "binding/SecurityPolicyRule.h"
27 #include "saml1/core/Assertions.h"
28 #include "saml2/core/Assertions.h"
30 #include <xercesc/util/XMLUniDefs.hpp>
31 #include <xmltooling/logging.h>
32 #include <xmltooling/XMLToolingConfig.h>
33 #include <xmltooling/util/ParserPool.h>
35 using namespace opensaml;
36 using namespace xmltooling::logging;
37 using namespace xmltooling;
41 class SAML_DLLLOCAL ConditionsRule : public SecurityPolicyRule
44 ConditionsRule(const DOMElement* e);
46 virtual ~ConditionsRule() {
47 for_each(m_rules.begin(), m_rules.end(), xmltooling::cleanup<SecurityPolicyRule>());
51 const char* getType() const {
52 return CONDITIONS_POLICY_RULE;
54 bool evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const;
58 vector<SecurityPolicyRule*> m_rules;
61 SecurityPolicyRule* SAML_DLLLOCAL ConditionsRuleFactory(const DOMElement* const & e)
63 return new ConditionsRule(e);
66 static const XMLCh Rule[] = UNICODE_LITERAL_10(P,o,l,i,c,y,R,u,l,e);
67 static const XMLCh type[] = UNICODE_LITERAL_4(t,y,p,e);
70 "<PolicyRule type=\"Conditions\" xmlns:saml2=\"urn:oasis:names:tc:SAML:2.0:assertion\" xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\">"
71 "<PolicyRule type=\"Audience\"/>"
72 "<PolicyRule type=\"Ignore\">saml:DoNotCacheCondition</PolicyRule>"
73 "<PolicyRule type=\"Ignore\">saml2:OneTimeUse</PolicyRule>"
74 "<PolicyRule type=\"Ignore\">saml2:ProxyRestriction</PolicyRule>"
78 ConditionsRule::ConditionsRule(const DOMElement* e) : m_doc(nullptr)
80 Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.Conditions");
82 if (!e || !e->hasChildNodes()) {
83 // Default the configuration.
84 istringstream in(config);
85 m_doc = XMLToolingConfig::getConfig().getParser().parse(in);
86 e = m_doc->getDocumentElement();
89 e = XMLHelper::getFirstChildElement(e, Rule);
91 auto_ptr_char temp(e->getAttributeNS(nullptr, type));
92 if (temp.get() && *temp.get()) {
94 log.info("building SecurityPolicyRule of type %s", temp.get());
95 m_rules.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(temp.get(),e));
97 catch (exception& ex) {
98 log.crit("error building SecurityPolicyRule: %s", ex.what());
101 e = XMLHelper::getNextSiblingElement(e, Rule);
105 bool ConditionsRule::evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const
107 const saml2::Assertion* a2=dynamic_cast<const saml2::Assertion*>(&message);
109 const saml2::Conditions* conds = a2->getConditions();
113 // First verify the time conditions, using the specified timestamp.
114 time_t now = policy.getTime();
115 unsigned int skew = XMLToolingConfig::getConfig().clock_skew_secs;
116 time_t t = conds->getNotBeforeEpoch();
118 throw SecurityPolicyException("Assertion is not yet valid.");
119 t = conds->getNotOnOrAfterEpoch();
121 throw SecurityPolicyException("Assertion is no longer valid.");
123 // Now we process conditions, starting with the known types and then extensions.
127 const vector<saml2::AudienceRestriction*>& acvec = conds->getAudienceRestrictions();
128 for (vector<saml2::AudienceRestriction*>::const_iterator ac = acvec.begin(); ac != acvec.end(); ++ac) {
130 for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
131 valid = (*r)->evaluate(*(*ac), request, policy);
133 throw SecurityPolicyException("AudienceRestriction condition not successfully validated by policy.");
136 const vector<saml2::OneTimeUse*>& otvec = conds->getOneTimeUses();
137 for (vector<saml2::OneTimeUse*>::const_iterator ot = otvec.begin(); ot!=otvec.end(); ++ot) {
139 for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
140 valid = (*r)->evaluate(*(*ot), request, policy);
142 throw SecurityPolicyException("OneTimeUse condition not successfully validated by policy.");
145 const vector<saml2::ProxyRestriction*> pvec = conds->getProxyRestrictions();
146 for (vector<saml2::ProxyRestriction*>::const_iterator p = pvec.begin(); p != pvec.end(); ++p) {
148 for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
149 valid = (*r)->evaluate(*(*p), request, policy);
151 throw SecurityPolicyException("ProxyRestriction condition not successfully validated by policy.");
154 const vector<saml2::Condition*>& convec = conds->getConditions();
155 for (vector<saml2::Condition*>::const_iterator c = convec.begin(); c != convec.end(); ++c) {
157 for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
158 valid = (*r)->evaluate(*(*c), request, policy);
160 throw SecurityPolicyException(
161 "Extension condition ($1) not successfully validated by policy.",
162 params(1,((*c)->getSchemaType() ? (*c)->getSchemaType()->toString().c_str() : "Unknown Type"))
170 const saml1::Assertion* a1=dynamic_cast<const saml1::Assertion*>(&message);
172 const saml1::Conditions* conds = a1->getConditions();
176 // First verify the time conditions, using the specified timestamp.
177 time_t now = policy.getTime();
178 unsigned int skew = XMLToolingConfig::getConfig().clock_skew_secs;
179 time_t t = conds->getNotBeforeEpoch();
181 throw SecurityPolicyException("Assertion is not yet valid.");
182 t = conds->getNotOnOrAfterEpoch();
184 throw SecurityPolicyException("Assertion is no longer valid.");
186 // Now we process conditions, starting with the known types and then extensions.
190 const vector<saml1::AudienceRestrictionCondition*>& acvec = conds->getAudienceRestrictionConditions();
191 for (vector<saml1::AudienceRestrictionCondition*>::const_iterator ac = acvec.begin(); ac != acvec.end(); ++ac) {
193 for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
194 valid = (*r)->evaluate(*(*ac), request, policy);
196 throw SecurityPolicyException("AudienceRestrictionCondition not successfully validated by policy.");
199 const vector<saml1::DoNotCacheCondition*>& dncvec = conds->getDoNotCacheConditions();
200 for (vector<saml1::DoNotCacheCondition*>::const_iterator dnc = dncvec.begin(); dnc != dncvec.end(); ++dnc) {
202 for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
203 valid = (*r)->evaluate(*(*dnc), request, policy);
205 throw SecurityPolicyException("DoNotCacheCondition not successfully validated by policy.");
208 const vector<saml1::Condition*>& convec = conds->getConditions();
209 for (vector<saml1::Condition*>::const_iterator c = convec.begin(); c != convec.end(); ++c) {
211 for (vector<SecurityPolicyRule*>::const_iterator r = m_rules.begin(); !valid && r != m_rules.end(); ++r)
212 valid = (*r)->evaluate(*(*c), request, policy);
214 throw SecurityPolicyException(
215 "Extension condition ($1) not successfully validated by policy.",
216 params(1,((*c)->getSchemaType() ? (*c)->getSchemaType()->toString().c_str() : (*c)->getElementQName().toString().c_str()))