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