Refine OAEP supporting elements when SHA-2 is off
[shibboleth/sp.git] / shibsp / handler / impl / MetadataGenerator.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  * MetadataGenerator.cpp
23  *
24  * Handler for generating "approximate" metadata based on SP configuration.
25  */
26
27 #include "internal.h"
28 #include "Application.h"
29 #include "exceptions.h"
30 #include "ServiceProvider.h"
31 #include "SPRequest.h"
32 #include "handler/RemotedHandler.h"
33 #include "handler/SecuredHandler.h"
34
35 #include <boost/scoped_ptr.hpp>
36 #include <boost/iterator/indirect_iterator.hpp>
37
38 #ifndef SHIBSP_LITE
39 # include "attribute/resolver/AttributeExtractor.h"
40 # include "metadata/MetadataProviderCriteria.h"
41 # include <boost/ptr_container/ptr_vector.hpp>
42 # include <saml/exceptions.h>
43 # include <saml/SAMLConfig.h>
44 # include <saml/signature/ContentReference.h>
45 # include <saml/saml2/metadata/Metadata.h>
46 # include <saml/saml2/metadata/MetadataProvider.h>
47 # include <xmltooling/XMLToolingConfig.h>
48 # include <xmltooling/encryption/Encryption.h>
49 # include <xmltooling/security/Credential.h>
50 # include <xmltooling/security/CredentialCriteria.h>
51 # include <xmltooling/security/SecurityHelper.h>
52 # include <xmltooling/signature/Signature.h>
53 # include <xmltooling/util/ParserPool.h>
54 # include <xmltooling/util/PathResolver.h>
55 # include <xsec/dsig/DSIGConstants.hpp>
56 # include <xercesc/framework/LocalFileInputSource.hpp>
57 # include <xercesc/framework/Wrapper4InputSource.hpp>
58 #endif
59
60
61 using namespace shibsp;
62 #ifndef SHIBSP_LITE
63 using namespace opensaml::saml2md;
64 using namespace opensaml;
65 using namespace xmlsignature;
66 using namespace xmlencryption;
67 #endif
68 using namespace xmltooling;
69 using namespace boost;
70 using namespace std;
71
72 namespace shibsp {
73
74 #if defined (_MSC_VER)
75     #pragma warning( push )
76     #pragma warning( disable : 4250 )
77 #endif
78
79     class SHIBSP_API MetadataGenerator : public SecuredHandler, public RemotedHandler
80     {
81     public:
82         MetadataGenerator(const DOMElement* e, const char* appId);
83         virtual ~MetadataGenerator() {}
84
85         pair<bool,long> run(SPRequest& request, bool isHandler=true) const;
86         void receive(DDF& in, ostream& out);
87
88     private:
89         pair<bool,long> processMessage(
90             const Application& application,
91             const char* handlerURL,
92             const char* entityID,
93             HTTPResponse& httpResponse
94             ) const;
95
96 #ifndef SHIBSP_LITE
97         void registerEncryptionMethod(const XMLCh* alg) {
98             if (XMLToolingConfig::getConfig().isXMLAlgorithmSupported(alg, XMLToolingConfig::ALGTYPE_ENCRYPT) ||
99                 XMLToolingConfig::getConfig().isXMLAlgorithmSupported(alg, XMLToolingConfig::ALGTYPE_KEYENCRYPT) ||
100                 XMLToolingConfig::getConfig().isXMLAlgorithmSupported(alg, XMLToolingConfig::ALGTYPE_KEYAGREE)) {
101                 // Non-default builder needed to override namespace/prefix.
102                 if (!m_encryptionBuilder)
103                     m_encryptionBuilder = XMLObjectBuilder::getBuilder(xmltooling::QName(samlconstants::SAML20MD_NS, EncryptionMethod::LOCAL_NAME));
104                 EncryptionMethod* em = dynamic_cast<EncryptionMethod*>(
105                     m_encryptionBuilder->buildObject(
106                         samlconstants::SAML20MD_NS, EncryptionMethod::LOCAL_NAME, samlconstants::SAML20MD_PREFIX
107                         )
108                     );
109                 em->setAlgorithm(alg);
110                 m_encryptions.push_back(em);
111
112                 if (XMLString::equals(alg, DSIGConstants::s_unicodeStrURIRSA_OAEP) ||
113                         XMLString::equals(alg, DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1)) {
114                     // Check for non-support of SHA-256. This is a reasonable guess as to whether
115                     // "all" standard digests and MGF variants will be supported or not, and if not, we
116                     // explicitly advertise only SHA-1.
117                     if (!XMLToolingConfig::getConfig().isXMLAlgorithmSupported(DSIGConstants::s_unicodeStrURISHA256, XMLToolingConfig::ALGTYPE_DIGEST)) {
118                         if (!m_digestBuilder)
119                             m_digestBuilder = XMLObjectBuilder::getBuilder(xmltooling::QName(samlconstants::SAML20MD_ALGSUPPORT_NS, DigestMethod::LOCAL_NAME));
120                         
121                         // Add MGF for new OAEP variant.
122                         if (XMLString::equals(alg, DSIGConstants::s_unicodeStrURIRSA_OAEP)) {
123                             MGF* mgf = MGFBuilder::buildMGF();
124                             mgf->setAlgorithm(DSIGConstants::s_unicodeStrURIMGF1_SHA1);
125                             em->getUnknownXMLObjects().push_back(mgf);
126                         }
127
128                         DigestMethod* dm = dynamic_cast<DigestMethod*>(
129                             m_digestBuilder->buildObject(xmlconstants::XMLSIG_NS, DigestMethod::LOCAL_NAME, xmlconstants::XMLSIG_PREFIX)
130                             );
131                         dm->setAlgorithm(DSIGConstants::s_unicodeStrURISHA1);
132                         em->getUnknownXMLObjects().push_back(dm);
133                     }
134                 }
135             }
136         }
137
138         void registerDigestMethod(const XMLCh* alg) {
139             if (XMLToolingConfig::getConfig().isXMLAlgorithmSupported(alg, XMLToolingConfig::ALGTYPE_DIGEST)) {
140                 DigestMethod* dm = DigestMethodBuilder::buildDigestMethod();
141                 dm->setAlgorithm(alg);
142                 m_digests.push_back(dm);
143             }
144         }
145
146         void registerSigningMethod(const XMLCh* alg) {
147             if (XMLToolingConfig::getConfig().isXMLAlgorithmSupported(alg, XMLToolingConfig::ALGTYPE_SIGN)) {
148                 SigningMethod* sm = SigningMethodBuilder::buildSigningMethod();
149                 sm->setAlgorithm(alg);
150                 m_signings.push_back(sm);
151             }
152         }
153
154         string m_salt;
155         short m_http,m_https;
156         vector<string> m_bases;
157         scoped_ptr<UIInfo> m_uiinfo;
158         scoped_ptr<Organization> m_org;
159         scoped_ptr<EntityAttributes> m_entityAttrs;
160         ptr_vector<ContactPerson> m_contacts;
161         ptr_vector<NameIDFormat> m_formats;
162         ptr_vector<RequestedAttribute> m_reqAttrs;
163         ptr_vector<AttributeConsumingService> m_attrConsumers;
164         ptr_vector<EncryptionMethod> m_encryptions;
165         ptr_vector<DigestMethod> m_digests;
166         ptr_vector<SigningMethod> m_signings;
167         const XMLObjectBuilder* m_encryptionBuilder;
168         const XMLObjectBuilder* m_digestBuilder;
169 #endif
170     };
171
172 #if defined (_MSC_VER)
173     #pragma warning( pop )
174 #endif
175
176     Handler* SHIBSP_DLLLOCAL MetadataGeneratorFactory(const pair<const DOMElement*,const char*>& p)
177     {
178         return new MetadataGenerator(p.first, p.second);
179     }
180
181 };
182
183 MetadataGenerator::MetadataGenerator(const DOMElement* e, const char* appId)
184     : SecuredHandler(e, Category::getInstance(SHIBSP_LOGCAT".MetadataGenerator"))
185 #ifndef SHIBSP_LITE
186         ,m_http(0), m_https(0), m_encryptionBuilder(nullptr), m_digestBuilder(nullptr)
187 #endif
188 {
189     string address(appId);
190     address += getString("Location").second;
191     setAddress(address.c_str());
192
193 #ifndef SHIBSP_LITE
194     static XMLCh EndpointBase[] =           UNICODE_LITERAL_12(E,n,d,p,o,i,n,t,B,a,s,e);
195
196     pair<bool,const char*> salt = getString("salt");
197     if (salt.first)
198         m_salt = salt.second;
199
200     pair<bool,bool> flag = getBool("http");
201     if (flag.first)
202         m_http = flag.second ? 1 : -1;
203     flag = getBool("https");
204     if (flag.first)
205         m_https = flag.second ? 1 : -1;
206
207     e = XMLHelper::getFirstChildElement(e);
208     while (e) {
209         if (XMLString::equals(e->getLocalName(), EndpointBase) && e->hasChildNodes()) {
210             auto_ptr_char base(e->getFirstChild()->getNodeValue());
211             if (base.get() && *base.get())
212                 m_bases.push_back(base.get());
213         }
214         else {
215             // Try and parse the object.
216             auto_ptr<XMLObject> child(XMLObjectBuilder::buildOneFromElement(const_cast<DOMElement*>(e)));
217             ContactPerson* cp = dynamic_cast<ContactPerson*>(child.get());
218             if (cp) {
219                 m_contacts.push_back(cp);
220                 child.release();
221             }
222             else {
223                 NameIDFormat* nif = dynamic_cast<NameIDFormat*>(child.get());
224                 if (nif) {
225                     m_formats.push_back(nif);
226                     child.release();
227                 }
228                 else {
229                     RequestedAttribute* req = dynamic_cast<RequestedAttribute*>(child.get());
230                     if (req) {
231                         m_reqAttrs.push_back(req);
232                         child.release();
233                     }
234                     else {
235                         AttributeConsumingService* acs = dynamic_cast<AttributeConsumingService*>(child.get());
236                         if (acs) {
237                             m_attrConsumers.push_back(acs);
238                             child.release();
239                         }
240                         else {
241                             UIInfo* info = dynamic_cast<UIInfo*>(child.get());
242                             if (info) {
243                                 if (!m_uiinfo) {
244                                     m_uiinfo.reset(info);
245                                     child.release();
246                                 }
247                                 else {
248                                     m_log.warn("skipping duplicate UIInfo element");
249                                 }
250                             }
251                             else {
252                                 Organization* org = dynamic_cast<Organization*>(child.get());
253                                 if (org) {
254                                     if (!m_org) {
255                                         m_org.reset(org);
256                                         child.release();
257                                     }
258                                     else {
259                                         m_log.warn("skipping duplicate Organization element");
260                                     }
261                                 }
262                                 else {
263                                     EntityAttributes* ea = dynamic_cast<EntityAttributes*>(child.get());
264                                     if (ea) {
265                                         if (!m_entityAttrs) {
266                                             m_entityAttrs.reset(ea);
267                                             child.release();
268                                         }
269                                         else {
270                                             m_log.warn("skipping duplicate EntityAttributes element");
271                                         }
272                                     }
273                                     else {
274                                         EncryptionMethod* em = dynamic_cast<EncryptionMethod*>(child.get());
275                                         if (em) {
276                                             m_encryptions.push_back(em);
277                                             child.release();
278                                         }
279                                         else {
280                                             DigestMethod* dm = dynamic_cast<DigestMethod*>(child.get());
281                                             if (dm) {
282                                                 m_digests.push_back(dm);
283                                                 child.release();
284                                             }
285                                             else {
286                                                 SigningMethod* sm = dynamic_cast<SigningMethod*>(child.get());
287                                                 if (sm) {
288                                                     m_signings.push_back(sm);
289                                                     child.release();
290                                                 }
291                                             }
292                                         }
293                                     }
294                                 }
295                             }
296                         }
297                     }
298                 }
299             }
300         }
301         e = XMLHelper::getNextSiblingElement(e);
302     }
303
304     // Default in precedence rules for various algorithms.
305     if (m_encryptions.empty()) {
306 #ifdef XSEC_OPENSSL_HAVE_GCM
307         registerEncryptionMethod(DSIGConstants::s_unicodeStrURIAES128_GCM);
308         registerEncryptionMethod(DSIGConstants::s_unicodeStrURIAES192_GCM);
309         registerEncryptionMethod(DSIGConstants::s_unicodeStrURIAES256_GCM);
310 #endif
311 #ifdef XSEC_OPENSSL_HAVE_AES
312         registerEncryptionMethod(DSIGConstants::s_unicodeStrURIAES128_CBC);
313         registerEncryptionMethod(DSIGConstants::s_unicodeStrURIAES192_CBC);
314         registerEncryptionMethod(DSIGConstants::s_unicodeStrURIAES256_CBC);
315 #endif
316         registerEncryptionMethod(DSIGConstants::s_unicodeStrURI3DES_CBC);
317 #ifdef URI_ID_RSA_OAEP
318         registerEncryptionMethod(DSIGConstants::s_unicodeStrURIRSA_OAEP);
319 #endif
320         registerEncryptionMethod(DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1);
321         registerEncryptionMethod(DSIGConstants::s_unicodeStrURIRSA_1_5);
322     }
323
324     if (m_digests.empty()) {
325         registerDigestMethod(DSIGConstants::s_unicodeStrURISHA512);
326         registerDigestMethod(DSIGConstants::s_unicodeStrURISHA384);
327         registerDigestMethod(DSIGConstants::s_unicodeStrURISHA256);
328         registerDigestMethod(DSIGConstants::s_unicodeStrURISHA224);
329         registerDigestMethod(DSIGConstants::s_unicodeStrURISHA1);
330     }
331
332     if (m_signings.empty()) {
333 #ifdef XSEC_OPENSSL_HAVE_EC
334         registerSigningMethod(DSIGConstants::s_unicodeStrURIECDSA_SHA512);
335         registerSigningMethod(DSIGConstants::s_unicodeStrURIECDSA_SHA384);
336         registerSigningMethod(DSIGConstants::s_unicodeStrURIECDSA_SHA256);
337 # ifdef URI_ID_ECDSA_SHA224
338         registerSigningMethod(DSIGConstants::s_unicodeStrURIECDSA_SHA224);
339 # endif
340 #endif
341         registerSigningMethod(DSIGConstants::s_unicodeStrURIRSA_SHA512);
342         registerSigningMethod(DSIGConstants::s_unicodeStrURIRSA_SHA384);
343         registerSigningMethod(DSIGConstants::s_unicodeStrURIRSA_SHA256);
344
345 #ifdef URI_ID_DSA_SHA256
346         registerSigningMethod(DSIGConstants::s_unicodeStrURIDSA_SHA256);
347 #endif
348
349 #ifdef XSEC_OPENSSL_HAVE_EC
350         registerSigningMethod(DSIGConstants::s_unicodeStrURIECDSA_SHA1);
351 #endif
352         registerSigningMethod(DSIGConstants::s_unicodeStrURIRSA_SHA1);
353         registerSigningMethod(DSIGConstants::s_unicodeStrURIDSA_SHA1);
354     }
355 #endif
356 }
357
358 pair<bool,long> MetadataGenerator::run(SPRequest& request, bool isHandler) const
359 {
360     // Check ACL in base class.
361     pair<bool,long> ret = SecuredHandler::run(request, isHandler);
362     if (ret.first)
363         return ret;
364
365     try {
366         if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) {
367             // When out of process, we run natively and directly process the message.
368             return processMessage(request.getApplication(), request.getHandlerURL(), request.getParameter("entityID"), request);
369         }
370         else {
371             // When not out of process, we remote all the message processing.
372             DDF out,in = DDF(m_address.c_str());
373             in.addmember("application_id").string(request.getApplication().getId());
374             in.addmember("handler_url").string(request.getHandlerURL());
375             if (request.getParameter("entityID"))
376                 in.addmember("entity_id").string(request.getParameter("entityID"));
377             DDFJanitor jin(in), jout(out);
378
379             out = request.getServiceProvider().getListenerService()->send(in);
380             return unwrap(request, out);
381         }
382     }
383     catch (std::exception& ex) {
384         m_log.error("error while processing request: %s", ex.what());
385         istringstream msg("Metadata Request Failed");
386         return make_pair(true, request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_ERROR));
387     }
388 }
389
390 void MetadataGenerator::receive(DDF& in, ostream& out)
391 {
392     // Find application.
393     const char* aid = in["application_id"].string();
394     const char* hurl = in["handler_url"].string();
395     const Application* app = aid ? SPConfig::getConfig().getServiceProvider()->getApplication(aid) : nullptr;
396     if (!app) {
397         // Something's horribly wrong.
398         m_log.error("couldn't find application (%s) for metadata request", aid ? aid : "(missing)");
399         throw ConfigurationException("Unable to locate application for metadata request, deleted?");
400     }
401     else if (!hurl) {
402         throw ConfigurationException("Missing handler_url parameter in remoted method call.");
403     }
404
405     // Wrap a response shim.
406     DDF ret(nullptr);
407     DDFJanitor jout(ret);
408     scoped_ptr<HTTPResponse> resp(getResponse(ret));
409
410     // Since we're remoted, the result should either be a throw, a false/0 return,
411     // which we just return as an empty structure, or a response/redirect,
412     // which we capture in the facade and send back.
413     processMessage(*app, hurl, in["entity_id"].string(), *resp);
414     out << ret;
415 }
416
417 pair<bool,long> MetadataGenerator::processMessage(
418     const Application& application, const char* handlerURL, const char* entityID, HTTPResponse& httpResponse
419     ) const
420 {
421 #ifndef SHIBSP_LITE
422     m_log.debug("processing metadata request");
423
424     const PropertySet* relyingParty = nullptr;
425     if (entityID) {
426         MetadataProvider* m = application.getMetadataProvider();
427         Locker locker(m);
428         MetadataProviderCriteria mc(application, entityID);
429         relyingParty = application.getRelyingParty(m->getEntityDescriptor(mc).first);
430     }
431     else {
432         relyingParty = &application;
433     }
434
435     scoped_ptr<EntityDescriptor> entity;
436     pair<bool,const char*> prop = getString("template");
437     if (prop.first) {
438         // Load a template to use for our metadata.
439         string templ(prop.second);
440         XMLToolingConfig::getConfig().getPathResolver()->resolve(templ, PathResolver::XMLTOOLING_CFG_FILE);
441         auto_ptr_XMLCh widenit(templ.c_str());
442         LocalFileInputSource src(widenit.get());
443         Wrapper4InputSource dsrc(&src,false);
444         DOMDocument* doc = XMLToolingConfig::getConfig().getParser().parse(dsrc);
445         XercesJanitor<DOMDocument> docjan(doc);
446         auto_ptr<XMLObject> xmlobj(XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(), true));
447         docjan.release();
448         entity.reset(dynamic_cast<EntityDescriptor*>(xmlobj.get()));
449         xmlobj.release();
450         if (!entity)
451             throw ConfigurationException("Template file ($1) did not contain an EntityDescriptor", params(1, templ.c_str()));
452     }
453     else {
454         entity.reset(EntityDescriptorBuilder::buildEntityDescriptor());
455     }
456
457     // We always have extensions for algorithm support.
458     if (!entity->getExtensions()) {
459         entity->setExtensions(ExtensionsBuilder::buildExtensions());
460         entity->getExtensions()->addNamespace(Namespace(samlconstants::SAML20MD_ALGSUPPORT_NS, samlconstants::SAML20MD_ALGSUPPORT_PREFIX));
461     }
462
463     if (!entity->getID()) {
464         string hashinput = m_salt + relyingParty->getString("entityID").second;
465         string hashed = '_' + SecurityHelper::doHash("SHA1", hashinput.c_str(), hashinput.length());
466         auto_ptr_XMLCh widenit(hashed.c_str());
467         entity->setID(widenit.get());
468     }
469
470     pair<bool,unsigned int> cache = getUnsignedInt("cacheDuration");
471     if (cache.first) {
472         entity->setCacheDuration(cache.second);
473     }
474     cache = getUnsignedInt("validUntil");
475     if (cache.first)
476         entity->setValidUntil(time(nullptr) + cache.second);
477     entity->setEntityID(relyingParty->getXMLString("entityID").second);
478
479     if (m_org && !entity->getOrganization())
480         entity->setOrganization(m_org->cloneOrganization());
481
482     for (ptr_vector<ContactPerson>::const_iterator cp = m_contacts.begin(); cp != m_contacts.end(); ++cp)
483         entity->getContactPersons().push_back(cp->cloneContactPerson());
484
485     if (m_entityAttrs) {
486         entity->getExtensions()->getUnknownXMLObjects().push_back(m_entityAttrs->cloneEntityAttributes());
487     }
488
489     SPSSODescriptor* role;
490     if (entity->getSPSSODescriptors().empty()) {
491         role = SPSSODescriptorBuilder::buildSPSSODescriptor();
492         entity->getSPSSODescriptors().push_back(role);
493     }
494     else {
495         role = entity->getSPSSODescriptors().front();
496     }
497
498     for (ptr_vector<NameIDFormat>::const_iterator nif = m_formats.begin(); nif != m_formats.end(); ++nif)
499         role->getNameIDFormats().push_back(nif->cloneNameIDFormat());
500
501     if (m_uiinfo) {
502         if (!role->getExtensions())
503             role->setExtensions(ExtensionsBuilder::buildExtensions());
504         role->getExtensions()->getUnknownXMLObjects().push_back(m_uiinfo->cloneUIInfo());
505     }
506
507     if (!m_digests.empty() || !m_signings.empty()) {
508         for (ptr_vector<DigestMethod>::const_iterator dm = m_digests.begin(); dm != m_digests.end(); ++dm)
509             entity->getExtensions()->getUnknownXMLObjects().push_back(dm->cloneDigestMethod());
510         for (ptr_vector<SigningMethod>::const_iterator sm = m_signings.begin(); sm != m_signings.end(); ++sm)
511             entity->getExtensions()->getUnknownXMLObjects().push_back(sm->cloneSigningMethod());
512     }
513
514     for (ptr_vector<AttributeConsumingService>::const_iterator acs = m_attrConsumers.begin(); acs != m_attrConsumers.end(); ++acs)
515         role->getAttributeConsumingServices().push_back(acs->cloneAttributeConsumingService());
516
517     if (!m_reqAttrs.empty()) {
518         int index = 1;
519         const vector<AttributeConsumingService*>& svcs = const_cast<const SPSSODescriptor*>(role)->getAttributeConsumingServices();
520         for (indirect_iterator<vector<AttributeConsumingService*>::const_iterator> s = make_indirect_iterator(svcs.begin());
521                 s != make_indirect_iterator(svcs.end()); ++s) {
522             pair<bool,int> i = s->getIndex();
523             if (i.first && index == i.second)
524                 index = i.second + 1;
525         }
526         AttributeConsumingService* svc = AttributeConsumingServiceBuilder::buildAttributeConsumingService();
527         role->getAttributeConsumingServices().push_back(svc);
528         svc->setIndex(index);
529         ServiceName* sn = ServiceNameBuilder::buildServiceName();
530         svc->getServiceNames().push_back(sn);
531         sn->setName(entity->getEntityID());
532         static const XMLCh english[] = UNICODE_LITERAL_2(e,n);
533         sn->setLang(english);
534         for (ptr_vector<RequestedAttribute>::const_iterator req = m_reqAttrs.begin(); req != m_reqAttrs.end(); ++req)
535             svc->getRequestedAttributes().push_back(req->cloneRequestedAttribute());
536     }
537
538     // Policy flags.
539     prop = relyingParty->getString("signing");
540     if (prop.first && (!strcmp(prop.second,"true") || !strcmp(prop.second,"front")))
541         role->AuthnRequestsSigned(true);
542     pair<bool,bool> flagprop = relyingParty->getBool("requireSignedAssertions");
543     if (flagprop.first && flagprop.second)
544         role->WantAssertionsSigned(true);
545
546     // Ask each handler to generate itself.
547     vector<const Handler*> handlers;
548     application.getHandlers(handlers);
549     for (indirect_iterator<vector<const Handler*>::const_iterator> h = make_indirect_iterator(handlers.begin());
550             h != make_indirect_iterator(handlers.end()); ++h) {
551         if (m_bases.empty()) {
552             if (strncmp(handlerURL, "https", 5) == 0) {
553                 if (m_https >= 0)
554                     h->generateMetadata(*role, handlerURL);
555                 if (m_http == 1) {
556                     string temp(handlerURL);
557                     temp.erase(4, 1);
558                     h->generateMetadata(*role, temp.c_str());
559                 }
560             }
561             else {
562                 if (m_http >= 0)
563                     h->generateMetadata(*role, handlerURL);
564                 if (m_https == 1) {
565                     string temp(handlerURL);
566                     temp.insert(temp.begin() + 4, 's');
567                     h->generateMetadata(*role, temp.c_str());
568                 }
569             }
570         }
571         else {
572             for (vector<string>::const_iterator b = m_bases.begin(); b != m_bases.end(); ++b)
573                 h->generateMetadata(*role, b->c_str());
574         }
575     }
576
577     AttributeExtractor* extractor = application.getAttributeExtractor();
578     if (extractor) {
579         Locker extlocker(extractor);
580         extractor->generateMetadata(*role);
581     }
582
583     CredentialResolver* credResolver = application.getCredentialResolver();
584     if (credResolver) {
585         Locker credLocker(credResolver);
586         CredentialCriteria cc;
587         prop = relyingParty->getString("keyName");
588         if (prop.first)
589             cc.getKeyNames().insert(prop.second);
590         vector<const Credential*> signingcreds,enccreds;
591         cc.setUsage(Credential::SIGNING_CREDENTIAL);
592         credResolver->resolve(signingcreds, &cc);
593         cc.setUsage(Credential::ENCRYPTION_CREDENTIAL);
594         credResolver->resolve(enccreds, &cc);
595
596         for (vector<const Credential*>::const_iterator c = signingcreds.begin(); c != signingcreds.end(); ++c) {
597             KeyInfo* kinfo = (*c)->getKeyInfo();
598             if (kinfo) {
599                 KeyDescriptor* kd = KeyDescriptorBuilder::buildKeyDescriptor();
600                 kd->setKeyInfo(kinfo);
601                 const XMLCh* use = KeyDescriptor::KEYTYPE_SIGNING;
602                 for (vector<const Credential*>::iterator match = enccreds.begin(); match != enccreds.end(); ++match) {
603                     if (*match == *c) {
604                         use = nullptr;
605                         enccreds.erase(match);
606                         break;
607                     }
608                 }
609                 kd->setUse(use);
610                 if (!use) {
611                     for (ptr_vector<EncryptionMethod>::const_iterator em = m_encryptions.begin(); em != m_encryptions.end(); ++em)
612                         kd->getEncryptionMethods().push_back(em->cloneEncryptionMethod());
613                 }
614                 role->getKeyDescriptors().push_back(kd);
615             }
616         }
617
618         for (vector<const Credential*>::const_iterator c = enccreds.begin(); c != enccreds.end(); ++c) {
619             KeyInfo* kinfo = (*c)->getKeyInfo();
620             if (kinfo) {
621                 KeyDescriptor* kd = KeyDescriptorBuilder::buildKeyDescriptor();
622                 kd->setUse(KeyDescriptor::KEYTYPE_ENCRYPTION);
623                 kd->setKeyInfo(kinfo);
624                 for (ptr_vector<EncryptionMethod>::const_iterator em = m_encryptions.begin(); em != m_encryptions.end(); ++em)
625                     kd->getEncryptionMethods().push_back(em->cloneEncryptionMethod());
626                 role->getKeyDescriptors().push_back(kd);
627             }
628         }
629     }
630
631     // Stream for response.
632     stringstream s;
633
634     // Self-sign it?
635     pair<bool,bool> flag = getBool("signing");
636     if (flag.first && flag.second) {
637         if (credResolver) {
638             Locker credLocker(credResolver);
639             // Fill in criteria to use.
640             CredentialCriteria cc;
641             cc.setUsage(Credential::SIGNING_CREDENTIAL);
642             prop = getString("keyName");
643             if (prop.first)
644                 cc.getKeyNames().insert(prop.second);
645             pair<bool,const XMLCh*> sigalg = getXMLString("signingAlg");
646             pair<bool,const XMLCh*> digalg = getXMLString("digestAlg");
647             if (sigalg.first)
648                 cc.setXMLAlgorithm(sigalg.second);
649             const Credential* cred = credResolver->resolve(&cc);
650             if (!cred)
651                 throw XMLSecurityException("Unable to obtain signing credential to use.");
652
653             // Pretty-print it first and then read it back in.
654             stringstream pretty;
655             XMLHelper::serialize(entity->marshall(), pretty, true);
656             DOMDocument* prettydoc = XMLToolingConfig::getConfig().getParser().parse(pretty);
657             scoped_ptr<XMLObject> prettyentity(XMLObjectBuilder::buildOneFromElement(prettydoc->getDocumentElement(), true));
658
659             Signature* sig = SignatureBuilder::buildSignature();
660             dynamic_cast<EntityDescriptor*>(prettyentity.get())->setSignature(sig);
661             if (sigalg.first)
662                 sig->setSignatureAlgorithm(sigalg.second);
663             if (digalg.first) {
664                 opensaml::ContentReference* cr = dynamic_cast<opensaml::ContentReference*>(sig->getContentReference());
665                 if (cr)
666                     cr->setDigestAlgorithm(digalg.second);
667             }
668
669             // Sign while marshalling.
670             vector<Signature*> sigs(1,sig);
671             prettyentity->marshall(prettydoc,&sigs,cred);
672             s << *prettyentity;
673         }
674         else {
675             throw FatalProfileException("Can't self-sign metadata, no credential resolver found.");
676         }
677     }
678     else {
679         // Pretty-print it directly to client.
680         XMLHelper::serialize(entity->marshall(), s, true);
681     }
682
683     prop = getString("mimeType");
684     httpResponse.setContentType(prop.first ? prop.second : "application/samlmetadata+xml");
685     return make_pair(true, httpResponse.sendResponse(s));
686 #else
687     return make_pair(false, 0L);
688 #endif
689 }