2 * Copyright 2001-2009 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.
18 * MetadataSchemaValidators.cpp
20 * Schema-based validators for SAML 2.0 Metadata classes.
24 #include "exceptions.h"
25 #include "saml2/metadata/Metadata.h"
27 #include <xmltooling/encryption/Encryption.h>
28 #include <xmltooling/validation/ValidatorSuite.h>
30 using namespace opensaml::saml2md;
31 using namespace opensaml::saml2;
32 using namespace opensaml;
33 using namespace xmltooling;
35 using samlconstants::SAML20MD_NS;
36 using samlconstants::SAML20MD_QUERY_EXT_NS;
37 using samlconstants::SAML20MD_ENTITY_ATTRIBUTE_NS;
42 XMLOBJECTVALIDATOR_SIMPLE(SAML_DLLLOCAL,ActionNamespace);
43 XMLOBJECTVALIDATOR_SIMPLE(SAML_DLLLOCAL,AffiliateMember);
44 XMLOBJECTVALIDATOR_SIMPLE(SAML_DLLLOCAL,AttributeProfile);
45 XMLOBJECTVALIDATOR_SIMPLE(SAML_DLLLOCAL,Company);
46 XMLOBJECTVALIDATOR_SIMPLE(SAML_DLLLOCAL,EmailAddress);
47 XMLOBJECTVALIDATOR_SIMPLE(SAML_DLLLOCAL,GivenName);
48 XMLOBJECTVALIDATOR_SIMPLE(SAML_DLLLOCAL,NameIDFormat);
49 XMLOBJECTVALIDATOR_SIMPLE(SAML_DLLLOCAL,SourceID);
50 XMLOBJECTVALIDATOR_SIMPLE(SAML_DLLLOCAL,SurName);
51 XMLOBJECTVALIDATOR_SIMPLE(SAML_DLLLOCAL,TelephoneNumber);
53 BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,localizedNameType);
54 XMLOBJECTVALIDATOR_REQUIRE(localizedNameType,TextContent);
55 XMLOBJECTVALIDATOR_REQUIRE(localizedNameType,Lang);
56 END_XMLOBJECTVALIDATOR;
58 BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,localizedURIType);
59 XMLOBJECTVALIDATOR_REQUIRE(localizedURIType,TextContent);
60 XMLOBJECTVALIDATOR_REQUIRE(localizedURIType,Lang);
61 END_XMLOBJECTVALIDATOR;
63 BEGIN_XMLOBJECTVALIDATOR_SUB(SAML_DLLLOCAL,OrganizationName,localizedNameType);
64 localizedNameTypeSchemaValidator::validate(xmlObject);
65 END_XMLOBJECTVALIDATOR;
67 BEGIN_XMLOBJECTVALIDATOR_SUB(SAML_DLLLOCAL,OrganizationDisplayName,localizedNameType);
68 localizedNameTypeSchemaValidator::validate(xmlObject);
69 END_XMLOBJECTVALIDATOR;
71 BEGIN_XMLOBJECTVALIDATOR_SUB(SAML_DLLLOCAL,OrganizationURL,localizedURIType);
72 localizedURITypeSchemaValidator::validate(xmlObject);
73 END_XMLOBJECTVALIDATOR;
75 class SAML_DLLLOCAL checkWildcardNS {
77 void operator()(const XMLObject* xmlObject) const {
78 const XMLCh* ns=xmlObject->getElementQName().getNamespaceURI();
79 if (XMLString::equals(ns,SAML20MD_NS) || !ns || !*ns) {
80 throw ValidationException(
81 "Object contains an illegal extension child element ($1).",
82 params(1,xmlObject->getElementQName().toString().c_str())
88 BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,Extensions);
89 if (!ptr->hasChildren())
90 throw ValidationException("Extensions must have at least one child element.");
91 const vector<XMLObject*>& anys=ptr->getUnknownXMLObjects();
92 for_each(anys.begin(),anys.end(),checkWildcardNS());
93 END_XMLOBJECTVALIDATOR;
95 BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,Organization);
96 XMLOBJECTVALIDATOR_NONEMPTY(Organization,OrganizationName);
97 XMLOBJECTVALIDATOR_NONEMPTY(Organization,OrganizationDisplayName);
98 XMLOBJECTVALIDATOR_NONEMPTY(Organization,OrganizationURL);
99 END_XMLOBJECTVALIDATOR;
101 BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,ContactPerson);
102 /* Pending errata decision.
103 if (!ptr->hasChildren())
104 throw ValidationException("ContactPerson must have at least one child element.");
106 if (!XMLString::equals(ptr->getContactType(),ContactPerson::CONTACT_TECHNICAL) &&
107 !XMLString::equals(ptr->getContactType(),ContactPerson::CONTACT_SUPPORT) &&
108 !XMLString::equals(ptr->getContactType(),ContactPerson::CONTACT_ADMINISTRATIVE) &&
109 !XMLString::equals(ptr->getContactType(),ContactPerson::CONTACT_BILLING) &&
110 !XMLString::equals(ptr->getContactType(),ContactPerson::CONTACT_OTHER))
111 throw ValidationException("ContactPerson contactType must be one of the defined values.");
112 END_XMLOBJECTVALIDATOR;
114 BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,AdditionalMetadataLocation);
115 XMLOBJECTVALIDATOR_REQUIRE(AdditionalMetadataLocation,Namespace);
116 XMLOBJECTVALIDATOR_REQUIRE(AdditionalMetadataLocation,Location);
117 END_XMLOBJECTVALIDATOR;
119 BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,KeyDescriptor);
120 XMLOBJECTVALIDATOR_REQUIRE(KeyDescriptor,KeyInfo);
122 !XMLString::equals(ptr->getUse(),KeyDescriptor::KEYTYPE_ENCRYPTION) &&
123 !XMLString::equals(ptr->getUse(),KeyDescriptor::KEYTYPE_SIGNING))
124 throw ValidationException("KeyDescriptor use must be empty or one of the defined values.");
125 END_XMLOBJECTVALIDATOR;
127 BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,RoleDescriptor);
128 XMLOBJECTVALIDATOR_REQUIRE(RoleDescriptor,ProtocolSupportEnumeration);
129 END_XMLOBJECTVALIDATOR;
131 BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,EndpointType);
132 XMLOBJECTVALIDATOR_REQUIRE(EndpointType,Binding);
133 XMLOBJECTVALIDATOR_REQUIRE(EndpointType,Location);
134 const vector<XMLObject*>& anys=ptr->getUnknownXMLObjects();
135 for_each(anys.begin(),anys.end(),checkWildcardNS());
136 END_XMLOBJECTVALIDATOR;
138 BEGIN_XMLOBJECTVALIDATOR_SUB(SAML_DLLLOCAL,IndexedEndpointType,EndpointType);
139 EndpointTypeSchemaValidator::validate(xmlObject);
140 XMLOBJECTVALIDATOR_REQUIRE_INTEGER(IndexedEndpointType,Index);
141 END_XMLOBJECTVALIDATOR;
143 BEGIN_XMLOBJECTVALIDATOR_SUB(SAML_DLLLOCAL,ArtifactResolutionService,IndexedEndpointType);
144 IndexedEndpointTypeSchemaValidator::validate(xmlObject);
145 END_XMLOBJECTVALIDATOR;
147 BEGIN_XMLOBJECTVALIDATOR_SUB(SAML_DLLLOCAL,SingleLogoutService,EndpointType);
148 EndpointTypeSchemaValidator::validate(xmlObject);
149 END_XMLOBJECTVALIDATOR;
151 BEGIN_XMLOBJECTVALIDATOR_SUB(SAML_DLLLOCAL,ManageNameIDService,EndpointType);
152 EndpointTypeSchemaValidator::validate(xmlObject);
153 END_XMLOBJECTVALIDATOR;
155 BEGIN_XMLOBJECTVALIDATOR_SUB(SAML_DLLLOCAL,SingleSignOnService,EndpointType);
156 EndpointTypeSchemaValidator::validate(xmlObject);
157 END_XMLOBJECTVALIDATOR;
159 BEGIN_XMLOBJECTVALIDATOR_SUB(SAML_DLLLOCAL,NameIDMappingService,EndpointType);
160 EndpointTypeSchemaValidator::validate(xmlObject);
161 END_XMLOBJECTVALIDATOR;
163 BEGIN_XMLOBJECTVALIDATOR_SUB(SAML_DLLLOCAL,AssertionIDRequestService,EndpointType);
164 EndpointTypeSchemaValidator::validate(xmlObject);
165 END_XMLOBJECTVALIDATOR;
167 BEGIN_XMLOBJECTVALIDATOR_SUB(SAML_DLLLOCAL,IDPSSODescriptor,RoleDescriptor);
168 RoleDescriptorSchemaValidator::validate(xmlObject);
169 XMLOBJECTVALIDATOR_NONEMPTY(IDPSSODescriptor,SingleSignOnService);
170 END_XMLOBJECTVALIDATOR;
172 BEGIN_XMLOBJECTVALIDATOR_SUB(SAML_DLLLOCAL,ServiceName,localizedNameType);
173 localizedNameTypeSchemaValidator::validate(xmlObject);
174 END_XMLOBJECTVALIDATOR;
176 BEGIN_XMLOBJECTVALIDATOR_SUB(SAML_DLLLOCAL,ServiceDescription,localizedNameType);
177 localizedNameTypeSchemaValidator::validate(xmlObject);
178 END_XMLOBJECTVALIDATOR;
180 BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,RequestedAttribute);
181 XMLOBJECTVALIDATOR_REQUIRE(RequestedAttribute,Name);
182 END_XMLOBJECTVALIDATOR;
184 BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,AttributeConsumingService);
185 XMLOBJECTVALIDATOR_REQUIRE_INTEGER(AttributeConsumingService,Index);
186 XMLOBJECTVALIDATOR_NONEMPTY(AttributeConsumingService,ServiceName);
187 XMLOBJECTVALIDATOR_NONEMPTY(AttributeConsumingService,RequestedAttribute);
188 END_XMLOBJECTVALIDATOR;
190 BEGIN_XMLOBJECTVALIDATOR_SUB(SAML_DLLLOCAL,AssertionConsumerService,IndexedEndpointType);
191 IndexedEndpointTypeSchemaValidator::validate(xmlObject);
192 END_XMLOBJECTVALIDATOR;
194 BEGIN_XMLOBJECTVALIDATOR_SUB(SAML_DLLLOCAL,SPSSODescriptor,RoleDescriptor);
195 RoleDescriptorSchemaValidator::validate(xmlObject);
196 XMLOBJECTVALIDATOR_NONEMPTY(SPSSODescriptor,AssertionConsumerService);
197 END_XMLOBJECTVALIDATOR;
199 BEGIN_XMLOBJECTVALIDATOR_SUB(SAML_DLLLOCAL,AuthnQueryService,EndpointType);
200 EndpointTypeSchemaValidator::validate(xmlObject);
201 END_XMLOBJECTVALIDATOR;
203 BEGIN_XMLOBJECTVALIDATOR_SUB(SAML_DLLLOCAL,AuthnAuthorityDescriptor,RoleDescriptor);
204 RoleDescriptorSchemaValidator::validate(xmlObject);
205 XMLOBJECTVALIDATOR_NONEMPTY(AuthnAuthorityDescriptor,AuthnQueryService);
206 END_XMLOBJECTVALIDATOR;
208 BEGIN_XMLOBJECTVALIDATOR_SUB(SAML_DLLLOCAL,AuthzService,EndpointType);
209 EndpointTypeSchemaValidator::validate(xmlObject);
210 END_XMLOBJECTVALIDATOR;
212 BEGIN_XMLOBJECTVALIDATOR_SUB(SAML_DLLLOCAL,PDPDescriptor,RoleDescriptor);
213 RoleDescriptorSchemaValidator::validate(xmlObject);
214 XMLOBJECTVALIDATOR_NONEMPTY(PDPDescriptor,AuthzService);
215 END_XMLOBJECTVALIDATOR;
217 BEGIN_XMLOBJECTVALIDATOR_SUB(SAML_DLLLOCAL,AttributeService,EndpointType);
218 EndpointTypeSchemaValidator::validate(xmlObject);
219 END_XMLOBJECTVALIDATOR;
221 BEGIN_XMLOBJECTVALIDATOR_SUB(SAML_DLLLOCAL,AttributeAuthorityDescriptor,RoleDescriptor);
222 RoleDescriptorSchemaValidator::validate(xmlObject);
223 XMLOBJECTVALIDATOR_NONEMPTY(AttributeAuthorityDescriptor,AttributeService);
224 END_XMLOBJECTVALIDATOR;
226 BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,AffiliationDescriptor);
227 XMLOBJECTVALIDATOR_REQUIRE(AffiliationDescriptor,AffiliationOwnerID);
228 XMLOBJECTVALIDATOR_NONEMPTY(AffiliationDescriptor,AffiliateMember);
229 END_XMLOBJECTVALIDATOR;
231 BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,EntityDescriptor);
232 XMLOBJECTVALIDATOR_REQUIRE(EntityDescriptor,EntityID);
233 if (ptr->getRoleDescriptors().empty() &&
234 ptr->getIDPSSODescriptors().empty() &&
235 ptr->getSPSSODescriptors().empty() &&
236 ptr->getAuthnAuthorityDescriptors().empty() &&
237 ptr->getAttributeAuthorityDescriptors().empty() &&
238 ptr->getPDPDescriptors().empty()) {
240 if (!ptr->getAffiliationDescriptor())
241 throw ValidationException("EntityDescriptor must have at least one child role or affiliation descriptor.");
243 else if (ptr->getAffiliationDescriptor()) {
244 throw ValidationException("EntityDescriptor cannot have both an AffiliationDescriptor and role descriptors.");
246 END_XMLOBJECTVALIDATOR;
248 BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,EntitiesDescriptor);
249 if (ptr->getEntityDescriptors().empty() && ptr->getEntitiesDescriptors().empty())
250 throw ValidationException("EntitiesDescriptor must contain at least one child descriptor.");
251 END_XMLOBJECTVALIDATOR;
253 BEGIN_XMLOBJECTVALIDATOR(SAML_DLLLOCAL,EntityAttributes);
254 if (!ptr->hasChildren())
255 throw ValidationException("EntityAttributes must contain at least one child element.");
256 END_XMLOBJECTVALIDATOR;
261 #define REGISTER_ELEMENT(cname) \
262 q=xmltooling::QName(SAML20MD_NS,cname::LOCAL_NAME); \
263 XMLObjectBuilder::registerBuilder(q,new cname##Builder()); \
264 SchemaValidators.registerValidator(q,new cname##SchemaValidator())
266 #define REGISTER_TYPE(cname) \
267 q=xmltooling::QName(SAML20MD_NS,cname::TYPE_NAME); \
268 XMLObjectBuilder::registerBuilder(q,new cname##Builder()); \
269 SchemaValidators.registerValidator(q,new cname##SchemaValidator())
271 #define REGISTER_ELEMENT_NOVAL(cname) \
272 q=xmltooling::QName(SAML20MD_NS,cname::LOCAL_NAME); \
273 XMLObjectBuilder::registerBuilder(q,new cname##Builder());
275 #define REGISTER_TYPE_NOVAL(cname) \
276 q=xmltooling::QName(SAML20MD_NS,cname::TYPE_NAME); \
277 XMLObjectBuilder::registerBuilder(q,new cname##Builder());
279 void opensaml::saml2md::registerMetadataClasses() {
281 REGISTER_ELEMENT(AdditionalMetadataLocation);
282 REGISTER_ELEMENT(AffiliateMember);
283 REGISTER_ELEMENT(AffiliationDescriptor);
284 REGISTER_ELEMENT(ArtifactResolutionService);
285 REGISTER_ELEMENT(AssertionConsumerService);
286 REGISTER_ELEMENT(AssertionIDRequestService);
287 REGISTER_ELEMENT(AttributeAuthorityDescriptor);;
288 REGISTER_ELEMENT(AttributeConsumingService);
289 REGISTER_ELEMENT(AttributeProfile);
290 REGISTER_ELEMENT(AttributeService);
291 REGISTER_ELEMENT(AuthnAuthorityDescriptor);
292 REGISTER_ELEMENT(AuthnQueryService);
293 REGISTER_ELEMENT(AuthzService);
294 REGISTER_ELEMENT(Company);
295 REGISTER_ELEMENT(ContactPerson);
296 REGISTER_ELEMENT(EmailAddress);
297 REGISTER_ELEMENT(EntitiesDescriptor);
298 REGISTER_ELEMENT(EntityDescriptor);
299 REGISTER_ELEMENT(Extensions);
300 REGISTER_ELEMENT(GivenName);
301 REGISTER_ELEMENT(IDPSSODescriptor);
302 REGISTER_ELEMENT(KeyDescriptor);
303 REGISTER_ELEMENT(ManageNameIDService);
304 REGISTER_ELEMENT(NameIDFormat);
305 REGISTER_ELEMENT(NameIDMappingService);
306 REGISTER_ELEMENT(Organization);
307 REGISTER_ELEMENT(OrganizationDisplayName);
308 REGISTER_ELEMENT(OrganizationName);
309 REGISTER_ELEMENT(OrganizationURL);
310 REGISTER_ELEMENT(PDPDescriptor);
311 REGISTER_ELEMENT(RequestedAttribute);
312 REGISTER_ELEMENT(RoleDescriptor);
313 REGISTER_ELEMENT(ServiceDescription);
314 REGISTER_ELEMENT(ServiceName);
315 REGISTER_ELEMENT(SingleLogoutService);
316 REGISTER_ELEMENT(SingleSignOnService);
317 REGISTER_ELEMENT(SPSSODescriptor);
318 REGISTER_ELEMENT(SurName);
319 REGISTER_ELEMENT(TelephoneNumber);
320 REGISTER_TYPE(AdditionalMetadataLocation);
321 REGISTER_TYPE(AffiliationDescriptor);
322 REGISTER_TYPE(AttributeAuthorityDescriptor);;
323 REGISTER_TYPE(AttributeConsumingService);
324 REGISTER_TYPE(AuthnAuthorityDescriptor);
325 REGISTER_TYPE(ContactPerson);
326 REGISTER_TYPE(EndpointType);
327 REGISTER_TYPE(EntitiesDescriptor);
328 REGISTER_TYPE(EntityDescriptor);
329 REGISTER_TYPE(Extensions);
330 REGISTER_TYPE(IDPSSODescriptor);
331 REGISTER_TYPE(IndexedEndpointType);
332 REGISTER_TYPE(KeyDescriptor);
333 REGISTER_TYPE(localizedNameType);
334 REGISTER_TYPE(localizedURIType);
335 REGISTER_TYPE(Organization);
336 REGISTER_TYPE(PDPDescriptor);
337 REGISTER_TYPE(RequestedAttribute);
338 REGISTER_TYPE(SPSSODescriptor);
340 q=xmltooling::QName(SAML20MD_NS,xmlencryption::EncryptionMethod::LOCAL_NAME);
341 XMLObjectBuilder::registerBuilder(q,new xmlencryption::EncryptionMethodBuilder());
343 q=xmltooling::QName(samlconstants::SAML1MD_NS,SourceID::LOCAL_NAME);
344 XMLObjectBuilder::registerBuilder(q,new SourceIDBuilder());
345 SchemaValidators.registerValidator(q,new SourceIDSchemaValidator());
347 q=xmltooling::QName(SAML20MD_QUERY_EXT_NS,ActionNamespace::LOCAL_NAME);
348 XMLObjectBuilder::registerBuilder(q,new ActionNamespaceBuilder());
349 SchemaValidators.registerValidator(q,new ActionNamespaceSchemaValidator());
351 q=xmltooling::QName(SAML20MD_QUERY_EXT_NS,AuthnQueryDescriptorType::TYPE_NAME);
352 XMLObjectBuilder::registerBuilder(q,new AuthnQueryDescriptorTypeBuilder());
353 SchemaValidators.registerValidator(q,new RoleDescriptorSchemaValidator());
355 q=xmltooling::QName(SAML20MD_QUERY_EXT_NS,AttributeQueryDescriptorType::TYPE_NAME);
356 XMLObjectBuilder::registerBuilder(q,new AttributeQueryDescriptorTypeBuilder());
357 SchemaValidators.registerValidator(q,new RoleDescriptorSchemaValidator());
359 q=xmltooling::QName(SAML20MD_QUERY_EXT_NS,AuthzDecisionQueryDescriptorType::TYPE_NAME);
360 XMLObjectBuilder::registerBuilder(q,new AuthzDecisionQueryDescriptorTypeBuilder());
361 SchemaValidators.registerValidator(q,new RoleDescriptorSchemaValidator());
363 q=xmltooling::QName(SAML20MD_ENTITY_ATTRIBUTE_NS,EntityAttributes::LOCAL_NAME);
364 XMLObjectBuilder::registerBuilder(q,new EntityAttributesBuilder());
365 SchemaValidators.registerValidator(q,new EntityAttributesSchemaValidator());
367 q=xmltooling::QName(SAML20MD_ENTITY_ATTRIBUTE_NS,EntityAttributes::TYPE_NAME);
368 XMLObjectBuilder::registerBuilder(q,new EntityAttributesBuilder());
369 SchemaValidators.registerValidator(q,new EntityAttributesSchemaValidator());