Reducing header overuse, non-inlining selected methods (CPPOST-35).
[shibboleth/cpp-opensaml.git] / saml / saml2 / profile / impl / Assertion20Validator.cpp
1 /*
2  *  Copyright 2001-2009 Internet2
3  * 
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 /**
18  * Assertion20Validator.cpp
19  * 
20  * SAML 2.0 basic assertion validator.
21  */
22
23 #include "internal.h"
24 #include "saml2/core/Assertions.h"
25 #include "saml2/profile/AssertionValidator.h"
26
27 #include <xmltooling/logging.h>
28 #include <xmltooling/XMLToolingConfig.h>
29 #include <xmltooling/util/NDC.h>
30
31 using namespace opensaml::saml2;
32 using namespace xmltooling::logging;
33 using namespace xmltooling;
34 using namespace std;
35
36 AssertionValidator::AssertionValidator(const XMLCh* recipient, const vector<const XMLCh*>* audiences, time_t ts)
37     : m_recipient(recipient), m_audiences(audiences), m_ts(ts)
38 {
39 }
40
41 AssertionValidator::~AssertionValidator()
42 {
43 }
44
45 void AssertionValidator::validate(const xmltooling::XMLObject* xmlObject) const
46 {
47     const Assertion* a=dynamic_cast<const Assertion*>(xmlObject);
48     if (!a)
49         throw ValidationException("Validator only applies to SAML 2.0 Assertion objects.");
50     validateAssertion(*a);
51 }
52
53 void AssertionValidator::validateAssertion(const Assertion& assertion) const
54 {
55 #ifdef _DEBUG
56     xmltooling::NDC ndc("validate");
57 #endif
58
59     const Conditions* conds = assertion.getConditions();
60     if (!conds)
61         return;
62     
63     // First verify the time conditions, using the specified timestamp, if non-zero.
64     if (m_ts>0) {
65         unsigned int skew = XMLToolingConfig::getConfig().clock_skew_secs;
66         time_t t=conds->getNotBeforeEpoch();
67         if (m_ts+skew < t)
68             throw ValidationException("Assertion is not yet valid.");
69         t=conds->getNotOnOrAfterEpoch();
70         if (t <= m_ts-skew)
71             throw ValidationException("Assertion is no longer valid.");
72     }
73
74     // Now we process conditions, starting with the known types and then extensions.
75     const vector<AudienceRestriction*>& acvec = conds->getAudienceRestrictions();
76     for (vector<AudienceRestriction*>::const_iterator ac = acvec.begin(); ac!=acvec.end(); ++ac)
77         validateCondition(*ac);
78
79     const vector<OneTimeUse*>& dncvec = conds->getOneTimeUses();
80     for (vector<OneTimeUse*>::const_iterator dnc = dncvec.begin(); dnc!=dncvec.end(); ++dnc)
81         validateCondition(*dnc);
82
83     const vector<Condition*>& convec = conds->getConditions();
84     for (vector<Condition*>::const_iterator c = convec.begin(); c!=convec.end(); ++c)
85         validateCondition(*c);
86 }
87
88 void AssertionValidator::validateCondition(const Condition* c) const
89 {
90     const AudienceRestriction* ac=dynamic_cast<const AudienceRestriction*>(c);
91     if (!ac) {
92         Category::getInstance(SAML_LOGCAT".AssertionValidator").error("unrecognized Condition in assertion (%s)",
93             c->getSchemaType() ? c->getSchemaType()->toString().c_str() : c->getElementQName().toString().c_str());
94         throw ValidationException("Assertion contains an unrecognized condition.");
95     }
96
97     bool found = false;
98     const vector<Audience*>& auds1 = ac->getAudiences();
99     for (vector<Audience*>::const_iterator a = auds1.begin(); !found && a!=auds1.end(); ++a) {
100         if (XMLString::equals(m_recipient, (*a)->getAudienceURI())) {
101             found = true;
102         }
103         else if (m_audiences) {
104             for (vector<const XMLCh*>::const_iterator a2 = m_audiences->begin(); !found && a2!=m_audiences->end(); ++a2) {
105                 found = XMLString::equals((*a)->getAudienceURI(), *a2);
106             }
107         }
108     }
109
110     if (!found) {
111         ostringstream os;
112         os << *ac;
113         Category::getInstance(SAML_LOGCAT".AssertionValidator").error("unacceptable AudienceRestriction in assertion (%s)", os.str().c_str());
114         throw ValidationException("Assertion contains an unacceptable AudienceRestriction.");
115     }
116 }