c29776417f71470203d55947dfce3219820ecbd1
[shibboleth/cpp-opensaml.git] / saml / saml2 / core / impl / Assertions20SchemaValidators.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  * Assertions20SchemaValidators.cpp
19  *
20  * Schema-based validators for SAML 2.0 Assertions classes
21  */
22
23 #include "internal.h"
24 #include "exceptions.h"
25 #include "saml2/core/Assertions.h"
26
27 #include <xmltooling/validation/ValidatorSuite.h>
28
29 using namespace opensaml::saml2;
30 using namespace opensaml;
31 using namespace xmltooling;
32 using namespace std;
33 using samlconstants::SAML20_NS;
34
35 namespace opensaml {
36     namespace saml2 {
37
38         XMLOBJECTVALIDATOR_SIMPLE(SAML_DLLLOCAL,Action);
39         XMLOBJECTVALIDATOR_SIMPLE(SAML_DLLLOCAL,AssertionIDRef);
40         XMLOBJECTVALIDATOR_SIMPLE(SAML_DLLLOCAL,AssertionURIRef);
41         XMLOBJECTVALIDATOR_SIMPLE(SAML_DLLLOCAL,Audience);
42         XMLOBJECTVALIDATOR_SIMPLE(SAML_DLLLOCAL,AuthnContextClassRef);
43         XMLOBJECTVALIDATOR_SIMPLE(SAML_DLLLOCAL,AuthnContextDeclRef);
44         XMLOBJECTVALIDATOR_SIMPLE(SAML_DLLLOCAL,AuthenticatingAuthority);
45         XMLOBJECTVALIDATOR_SIMPLE(SAML_DLLLOCAL,NameIDType);
46         XMLOBJECTVALIDATOR_SIMPLE(SAML_DLLLOCAL,NameID);
47         XMLOBJECTVALIDATOR_SIMPLE(SAML_DLLLOCAL,Issuer);
48
49         BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,EncryptedElementType);
50             XMLOBJECTVALIDATOR_REQUIRE(EncryptedElementType,EncryptedData);
51         END_XMLOBJECTVALIDATOR;
52
53         BEGIN_XMLOBJECTVALIDATOR_SUB(SAML_DLLLOCAL,EncryptedID,EncryptedElementType);
54             EncryptedElementTypeSchemaValidator::validate(xmlObject);
55         END_XMLOBJECTVALIDATOR;
56
57         BEGIN_XMLOBJECTVALIDATOR_SUB(SAML_DLLLOCAL,EncryptedAttribute,EncryptedElementType);
58             EncryptedElementTypeSchemaValidator::validate(xmlObject);
59         END_XMLOBJECTVALIDATOR;
60
61         BEGIN_XMLOBJECTVALIDATOR_SUB(SAML_DLLLOCAL,EncryptedAssertion,EncryptedElementType);
62             EncryptedElementTypeSchemaValidator::validate(xmlObject);
63         END_XMLOBJECTVALIDATOR;
64
65         BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,AudienceRestriction);
66             XMLOBJECTVALIDATOR_NONEMPTY(AudienceRestriction,Audience);
67         END_XMLOBJECTVALIDATOR;
68
69         BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,ProxyRestriction);
70             if (ptr->getAudiences().empty()) {
71                 XMLOBJECTVALIDATOR_REQUIRE_INTEGER(ProxyRestriction,Count);
72             }
73         END_XMLOBJECTVALIDATOR;
74
75         BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,Delegate);
76             int count=0;
77             if (ptr->getBaseID())
78                 count++;
79             if (ptr->getNameID())
80                 count++;
81             if (ptr->getEncryptedID())
82                 count++;
83             if (count != 1)
84                 throw ValidationException("Delegate must contain exactly one identifier element.");
85         END_XMLOBJECTVALIDATOR;
86
87         BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,DelegationRestrictionType);
88             XMLOBJECTVALIDATOR_NONEMPTY(DelegationRestrictionType,Delegate);
89         END_XMLOBJECTVALIDATOR;
90
91         BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,Conditions);
92             if (!ptr->hasChildren()) {
93                 XMLOBJECTVALIDATOR_ONEOF(Conditions,NotBefore,NotOnOrAfter);
94             }
95             else if (ptr->getOneTimeUses().size() > 1) {
96                 throw ValidationException("Multiple OneTimeUse condition elements are not permitted.");
97             }
98             else if (ptr->getProxyRestrictions().size() > 1) {
99                 throw ValidationException("Multiple ProxyRestriction condition elements are not permitted.");
100             }
101         END_XMLOBJECTVALIDATOR;
102
103         BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,KeyInfoConfirmationDataType);
104             XMLOBJECTVALIDATOR_NONEMPTY(KeyInfoConfirmationDataType,KeyInfo);
105         END_XMLOBJECTVALIDATOR;
106
107         BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,SubjectConfirmation);
108             XMLOBJECTVALIDATOR_REQUIRE(SubjectConfirmation,Method);
109             int count=0;
110             if (ptr->getBaseID())
111                 count++;
112             if (ptr->getNameID())
113                 count++;
114             if (ptr->getEncryptedID())
115                 count++;
116             if (count > 1)
117                 throw ValidationException("SubjectConfirmation cannot contain multiple identifier elements.");
118         END_XMLOBJECTVALIDATOR;
119
120         BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,Subject);
121             int count=0;
122             if (ptr->getBaseID())
123                 count++;
124             if (ptr->getNameID())
125                 count++;
126             if (ptr->getEncryptedID())
127                 count++;
128             if (count > 1)
129                 throw ValidationException("Subject cannot contain multiple identifier elements.");
130         END_XMLOBJECTVALIDATOR;
131
132         BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,SubjectLocality);
133             XMLOBJECTVALIDATOR_ONEOF(SubjectLocality,Address,DNSName);
134         END_XMLOBJECTVALIDATOR;
135
136         BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,AuthnContext);
137             if (!ptr->getAuthnContextClassRef()) {
138                 XMLOBJECTVALIDATOR_ONLYONEOF(AuthnContext,AuthnContextDeclRef,AuthnContextDecl);
139             }
140         END_XMLOBJECTVALIDATOR;
141
142         BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,AuthnStatement);
143             XMLOBJECTVALIDATOR_REQUIRE(AuthnStatement,AuthnInstant);
144             XMLOBJECTVALIDATOR_REQUIRE(AuthnStatement,AuthnContext);
145         END_XMLOBJECTVALIDATOR;
146
147         BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,Evidence);
148             if (!ptr->hasChildren())
149                 throw ValidationException("Evidence must have at least one child element.");
150         END_XMLOBJECTVALIDATOR;
151
152         BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,AuthzDecisionStatement);
153             XMLOBJECTVALIDATOR_REQUIRE(AuthzDecisionStatement,Resource);
154             XMLOBJECTVALIDATOR_REQUIRE(AuthzDecisionStatement,Decision);
155             if (!XMLString::equals(ptr->getDecision(),AuthzDecisionStatement::DECISION_PERMIT) &&
156                 !XMLString::equals(ptr->getDecision(),AuthzDecisionStatement::DECISION_DENY) &&
157                 !XMLString::equals(ptr->getDecision(),AuthzDecisionStatement::DECISION_INDETERMINATE))
158                 throw ValidationException("Decision must be one of Deny, Permit, or Indeterminate.");
159             XMLOBJECTVALIDATOR_NONEMPTY(AuthzDecisionStatement,Action);
160         END_XMLOBJECTVALIDATOR;
161
162         BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,Attribute);
163             XMLOBJECTVALIDATOR_REQUIRE(Attribute,Name);
164         END_XMLOBJECTVALIDATOR;
165
166         BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,AttributeStatement);
167             XMLOBJECTVALIDATOR_NONEMPTY(AttributeStatement,Attribute);
168         END_XMLOBJECTVALIDATOR;
169
170         BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,Assertion);
171             XMLOBJECTVALIDATOR_REQUIRE(Assertion,Version);
172             if (!XMLString::equals(samlconstants::SAML20_VERSION, ptr->getVersion()))
173                 throw ValidationException("Assertion has wrong SAML Version.");
174             XMLOBJECTVALIDATOR_REQUIRE(Assertion,ID);
175             XMLOBJECTVALIDATOR_REQUIRE(Assertion,IssueInstant);
176             XMLOBJECTVALIDATOR_REQUIRE(Assertion,Issuer);
177             if ((!ptr->getAuthnStatements().empty() ||
178                 !ptr->getAttributeStatements().empty() ||
179                 !ptr->getAuthzDecisionStatements().empty()) && !ptr->getSubject())
180                 throw ValidationException("Assertion with standard statements must have a Subject.");
181         END_XMLOBJECTVALIDATOR;
182
183         class SAML_DLLLOCAL checkWildcardNS {
184         public:
185             void operator()(const XMLObject* xmlObject) const {
186                 const XMLCh* ns=xmlObject->getElementQName().getNamespaceURI();
187                 if (XMLString::equals(ns,SAML20_NS) || !ns || !*ns) {
188                     throw ValidationException(
189                         "Object contains an illegal extension child element ($1).",
190                         params(1,xmlObject->getElementQName().toString().c_str())
191                         );
192                 }
193             }
194         };
195
196         BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,Advice);
197             const vector<XMLObject*>& anys=ptr->getUnknownXMLObjects();
198             for_each(anys.begin(),anys.end(),checkWildcardNS());
199         END_XMLOBJECTVALIDATOR;
200
201     };
202 };
203
204 #define REGISTER_ELEMENT(cname) \
205     q=xmltooling::QName(SAML20_NS,cname::LOCAL_NAME); \
206     XMLObjectBuilder::registerBuilder(q,new cname##Builder()); \
207     SchemaValidators.registerValidator(q,new cname##SchemaValidator())
208
209 #define REGISTER_TYPE(cname) \
210     q=xmltooling::QName(SAML20_NS,cname::TYPE_NAME); \
211     XMLObjectBuilder::registerBuilder(q,new cname##Builder()); \
212     SchemaValidators.registerValidator(q,new cname##SchemaValidator())
213
214 #define REGISTER_ELEMENT_NOVAL(cname) \
215     q=xmltooling::QName(SAML20_NS,cname::LOCAL_NAME); \
216     XMLObjectBuilder::registerBuilder(q,new cname##Builder());
217
218 #define REGISTER_TYPE_NOVAL(cname) \
219     q=xmltooling::QName(SAML20_NS,cname::TYPE_NAME); \
220     XMLObjectBuilder::registerBuilder(q,new cname##Builder());
221
222 void opensaml::saml2::registerAssertionClasses() {
223     xmltooling::QName q;
224     REGISTER_ELEMENT(Action);
225     REGISTER_ELEMENT(Advice);
226     REGISTER_ELEMENT(Assertion);
227     REGISTER_ELEMENT(AssertionIDRef);
228     REGISTER_ELEMENT(AssertionURIRef);
229     REGISTER_ELEMENT(Attribute);
230     REGISTER_ELEMENT(AttributeStatement);
231     REGISTER_ELEMENT_NOVAL(AttributeValue);
232     REGISTER_ELEMENT(Audience);
233     REGISTER_ELEMENT(AudienceRestriction);
234     REGISTER_ELEMENT(AuthenticatingAuthority);
235     REGISTER_ELEMENT(AuthnContext);
236     REGISTER_ELEMENT(AuthnContextClassRef);
237     REGISTER_ELEMENT_NOVAL(AuthnContextDecl);
238     REGISTER_ELEMENT(AuthnContextDeclRef);
239     REGISTER_ELEMENT(AuthnStatement);
240     REGISTER_ELEMENT(AuthzDecisionStatement);
241     REGISTER_ELEMENT_NOVAL(Condition);
242     REGISTER_ELEMENT(Conditions);
243     REGISTER_ELEMENT(EncryptedAssertion);
244     REGISTER_ELEMENT(EncryptedAttribute);
245     REGISTER_ELEMENT(EncryptedID);
246     REGISTER_ELEMENT(Evidence);
247     REGISTER_ELEMENT(Issuer);
248     REGISTER_ELEMENT(NameID);
249     REGISTER_ELEMENT_NOVAL(OneTimeUse);
250     REGISTER_ELEMENT(ProxyRestriction);
251     REGISTER_ELEMENT_NOVAL(Statement);
252     REGISTER_ELEMENT(Subject);
253     REGISTER_ELEMENT(SubjectConfirmation);
254     REGISTER_ELEMENT_NOVAL(SubjectConfirmationData);
255     REGISTER_ELEMENT(SubjectLocality);
256     REGISTER_TYPE(Action);
257     REGISTER_TYPE(Advice);
258     REGISTER_TYPE(Assertion);
259     REGISTER_TYPE(Attribute);
260     REGISTER_TYPE(AttributeStatement);
261     REGISTER_TYPE(AudienceRestriction);
262     REGISTER_TYPE(AuthnContext);
263     REGISTER_TYPE(AuthnStatement);
264     REGISTER_TYPE(AuthzDecisionStatement);
265     REGISTER_TYPE(Conditions);
266     REGISTER_TYPE(Evidence);
267     REGISTER_TYPE(KeyInfoConfirmationDataType);
268     REGISTER_TYPE(NameIDType);
269     REGISTER_TYPE_NOVAL(OneTimeUse);
270     REGISTER_TYPE(ProxyRestriction);
271     REGISTER_TYPE(Subject);
272     REGISTER_TYPE(SubjectConfirmation);
273     REGISTER_TYPE(SubjectLocality);
274
275     q=xmltooling::QName(samlconstants::SAML20_DELEGATION_CONDITION_NS,Delegate::LOCAL_NAME);
276     XMLObjectBuilder::registerBuilder(q,new DelegateBuilder());
277     SchemaValidators.registerValidator(q,new DelegateSchemaValidator());
278     q=xmltooling::QName(samlconstants::SAML20_DELEGATION_CONDITION_NS,Delegate::TYPE_NAME);
279     XMLObjectBuilder::registerBuilder(q,new DelegateBuilder());
280     SchemaValidators.registerValidator(q,new DelegateSchemaValidator());
281
282     q=xmltooling::QName(samlconstants::SAML20_DELEGATION_CONDITION_NS,DelegationRestrictionType::TYPE_NAME);
283     XMLObjectBuilder::registerBuilder(q,new DelegationRestrictionTypeBuilder());
284     SchemaValidators.registerValidator(q,new DelegationRestrictionTypeSchemaValidator());
285 }