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