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