Basic assertion validator.
[shibboleth/cpp-opensaml.git] / saml / saml2 / profile / AssertionValidator.cpp
1 /*
2  *  Copyright 2001-2007 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  * AssertionValidator.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 <log4cpp/Category.hh>
28 #include <xmltooling/util/NDC.h>
29
30 using namespace opensaml::saml2;
31 using namespace xmltooling;
32 using namespace log4cpp;
33 using namespace std;
34
35 void AssertionValidator::validate(const xmltooling::XMLObject* xmlObject) const
36 {
37     const Assertion* a=dynamic_cast<const Assertion*>(xmlObject);
38     if (!a)
39         throw ValidationException("Validator only applies to SAML 2.0 Assertion objects.");
40     validateAssertion(*a);
41 }
42
43 void AssertionValidator::validateAssertion(const Assertion& assertion) const
44 {
45 #ifdef _DEBUG
46     xmltooling::NDC ndc("validate");
47 #endif
48
49     const Conditions* conds = assertion.getConditions();
50     // First verify the time conditions, using the specified timestamp, if non-zero.
51     if (m_ts>0 && conds) {
52         unsigned int skew = XMLToolingConfig::getConfig().clock_skew_secs;
53         time_t t=conds->getNotBeforeEpoch();
54         if (m_ts+skew < t)
55             throw ValidationException("Assertion is not yet valid.");
56         t=conds->getNotOnOrAfterEpoch();
57         if (t <= m_ts-skew)
58             throw ValidationException("Assertion is no longer valid.");
59     }
60
61     // Now we process conditions. Only audience restrictions at the moment.
62     const vector<Condition*>& convec = conds->getConditions();
63     for (vector<Condition*>::const_iterator c = convec.begin(); c!=convec.end(); ++c) {
64         if (!validateCondition(*c)) {
65             Category::getInstance(SAML_LOGCAT".AssertionValidator").error("unrecognized Condition in assertion (%s)",
66                 (*c)->getSchemaType() ? (*c)->getSchemaType()->toString().c_str() : (*c)->getElementQName().toString().c_str());
67             throw ValidationException("Assertion contains an unrecognized condition.");
68         }
69     }
70 }
71
72 bool AssertionValidator::validateCondition(const Condition* condition) const
73 {
74     const AudienceRestriction* ac=dynamic_cast<const AudienceRestriction*>(condition);
75     if (!ac)
76         return false;
77
78     bool found = false;
79     const vector<Audience*>& auds1 = ac->getAudiences();
80     for (vector<Audience*>::const_iterator a = auds1.begin(); !found && a!=auds1.end(); ++a) {
81         for (vector<const XMLCh*>::const_iterator a2 = m_audiences.begin(); !found && a2!=m_audiences.end(); ++a2) {
82             found = XMLString::equals((*a)->getAudienceURI(), *a2);
83         }
84     }
85
86     if (!found) {
87         ostringstream os;
88         os << *ac;
89         Category::getInstance(SAML_LOGCAT".AssertionValidator").error("unacceptable AudienceRestriction in assertion (%s)", os.str().c_str());
90         throw ValidationException("Assertion contains an unacceptable AudienceRestriction.");
91     }
92
93     return found;
94 }