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.
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 * MetadataAttributeExtractor.cpp
24 * AttributeExtractor for SAML metadata content.
28 #include "Application.h"
29 #include "ServiceProvider.h"
30 #include "attribute/SimpleAttribute.h"
31 #include "attribute/AttributeDecoder.h"
32 #include "attribute/resolver/AttributeExtractor.h"
34 #include <boost/bind.hpp>
35 #include <boost/shared_ptr.hpp>
36 #include <boost/iterator/indirect_iterator.hpp>
37 #include <boost/tuple/tuple.hpp>
38 #include <saml/saml2/metadata/Metadata.h>
39 #include <xmltooling/util/XMLHelper.h>
40 #include <xercesc/util/XMLStringTokenizer.hpp>
41 #include <xercesc/util/XMLUniDefs.hpp>
43 using namespace shibsp;
44 using namespace opensaml::saml2md;
45 using namespace opensaml;
46 using namespace xmltooling;
47 using namespace boost;
52 #if defined (_MSC_VER)
53 #pragma warning( push )
54 #pragma warning( disable : 4250 )
57 class MetadataExtractor : public AttributeExtractor
60 MetadataExtractor(const DOMElement* e);
61 ~MetadataExtractor() {}
71 void extractAttributes(
72 const Application& application,
73 const RoleDescriptor* issuer,
74 const XMLObject& xmlObject,
75 vector<shibsp::Attribute*>& attributes
77 extractAttributes(application, nullptr, issuer, xmlObject, attributes);
80 void extractAttributes(
81 const Application& application,
82 const GenericRequest* request,
83 const RoleDescriptor* issuer,
84 const XMLObject& xmlObject,
85 vector<shibsp::Attribute*>& attributes
87 void getAttributeIds(vector<string>& attributes) const;
90 string m_attributeProfiles,
99 typedef tuple< string,xstring,boost::shared_ptr<AttributeDecoder> > contact_tuple_t;
100 typedef tuple< string,int,int,boost::shared_ptr<AttributeDecoder> > logo_tuple_t;
101 vector<contact_tuple_t> m_contacts; // tuple is attributeID, contact type, decoder
102 vector<logo_tuple_t> m_logos; // tuple is attributeID, height, width, decoder
104 template <class T> void doLangSensitive(const GenericRequest*, const vector<T*>&, const string&, vector<shibsp::Attribute*>&) const;
105 void doContactPerson(const RoleDescriptor*, const contact_tuple_t&, vector<shibsp::Attribute*>&) const;
106 void doLogo(const GenericRequest*, const vector<Logo*>&,const logo_tuple_t&, vector<shibsp::Attribute*>&) const;
109 #if defined (_MSC_VER)
110 #pragma warning( pop )
113 AttributeExtractor* SHIBSP_DLLLOCAL MetadataAttributeExtractorFactory(const DOMElement* const & e)
115 return new MetadataExtractor(e);
118 static const XMLCh _id[] = UNICODE_LITERAL_2(i,d);
119 static const XMLCh _formatter[] = UNICODE_LITERAL_9(f,o,r,m,a,t,t,e,r);
122 MetadataExtractor::MetadataExtractor(const DOMElement* e)
123 : m_attributeProfiles(XMLHelper::getAttrString(e, nullptr, AttributeProfile::LOCAL_NAME)),
124 m_errorURL(XMLHelper::getAttrString(e, nullptr, RoleDescriptor::ERRORURL_ATTRIB_NAME)),
125 m_displayName(XMLHelper::getAttrString(e, nullptr, DisplayName::LOCAL_NAME)),
126 m_description(XMLHelper::getAttrString(e, nullptr, Description::LOCAL_NAME)),
127 m_informationURL(XMLHelper::getAttrString(e, nullptr, InformationURL::LOCAL_NAME)),
128 m_privacyURL(XMLHelper::getAttrString(e, nullptr, PrivacyStatementURL::LOCAL_NAME)),
129 m_orgName(XMLHelper::getAttrString(e, nullptr, OrganizationName::LOCAL_NAME)),
130 m_orgDisplayName(XMLHelper::getAttrString(e, nullptr, OrganizationDisplayName::LOCAL_NAME)),
131 m_orgURL(XMLHelper::getAttrString(e, nullptr, OrganizationURL::LOCAL_NAME))
133 e = e ? XMLHelper::getFirstChildElement(e) : nullptr;
135 if (XMLHelper::isNodeNamed(e, shibspconstants::SHIB2SPCONFIG_NS, ContactPerson::LOCAL_NAME)) {
136 string id(XMLHelper::getAttrString(e, nullptr, _id));
137 const XMLCh* type = e->getAttributeNS(nullptr, ContactPerson::CONTACTTYPE_ATTRIB_NAME);
138 if (!id.empty() && type && *type) {
139 boost::shared_ptr<AttributeDecoder> decoder(SPConfig::getConfig().AttributeDecoderManager.newPlugin(DOMAttributeDecoderType, e));
140 m_contacts.push_back(contact_tuple_t(id, type, decoder));
143 else if (XMLHelper::isNodeNamed(e, shibspconstants::SHIB2SPCONFIG_NS, Logo::LOCAL_NAME)) {
144 string id(XMLHelper::getAttrString(e, nullptr, _id));
145 int h(XMLHelper::getAttrInt(e, 0, Logo::HEIGHT_ATTRIB_NAME));
146 int w(XMLHelper::getAttrInt(e, 0, Logo::WIDTH_ATTRIB_NAME));
148 boost::shared_ptr<AttributeDecoder> decoder(SPConfig::getConfig().AttributeDecoderManager.newPlugin(DOMAttributeDecoderType, e));
149 m_logos.push_back(logo_tuple_t(id, h, w, decoder));
152 e = XMLHelper::getNextSiblingElement(e);
156 void MetadataExtractor::getAttributeIds(vector<string>& attributes) const
158 if (!m_attributeProfiles.empty())
159 attributes.push_back(m_attributeProfiles);
160 if (!m_errorURL.empty())
161 attributes.push_back(m_errorURL);
162 if (!m_displayName.empty())
163 attributes.push_back(m_displayName);
164 if (!m_description.empty())
165 attributes.push_back(m_description);
166 if (!m_informationURL.empty())
167 attributes.push_back(m_informationURL);
168 if (!m_privacyURL.empty())
169 attributes.push_back(m_privacyURL);
170 if (!m_orgName.empty())
171 attributes.push_back(m_orgName);
172 if (!m_orgDisplayName.empty())
173 attributes.push_back(m_orgDisplayName);
174 if (!m_orgURL.empty())
175 attributes.push_back(m_orgURL);
176 static void (vector<string>::* push_back)(const string&) = &vector<string>::push_back;
177 static const string& (contact_tuple_t::* tget)() const = &contact_tuple_t::get<0>;
178 static const string& (logo_tuple_t::* tget2)() const = &logo_tuple_t::get<0>;
179 for_each(m_contacts.begin(), m_contacts.end(), boost::bind(push_back, boost::ref(attributes), boost::bind(tget, _1)));
180 for_each(m_logos.begin(), m_logos.end(), boost::bind(push_back, boost::ref(attributes), boost::bind(tget2, _1)));
183 void MetadataExtractor::extractAttributes(
184 const Application& application,
185 const GenericRequest* request,
186 const RoleDescriptor* issuer,
187 const XMLObject& xmlObject,
188 vector<shibsp::Attribute*>& attributes
191 const RoleDescriptor* roleToExtract = dynamic_cast<const RoleDescriptor*>(&xmlObject);
195 if (!m_attributeProfiles.empty()) {
196 const vector<AttributeProfile*>* profiles = nullptr;
197 const IDPSSODescriptor* idpRole = dynamic_cast<const IDPSSODescriptor*>(roleToExtract);
199 profiles = &(idpRole->getAttributeProfiles());
202 const AttributeAuthorityDescriptor* aaRole = dynamic_cast<const AttributeAuthorityDescriptor*>(roleToExtract);
204 profiles = &(aaRole->getAttributeProfiles());
207 if (profiles && !profiles->empty()) {
208 auto_ptr<SimpleAttribute> attr(new SimpleAttribute(vector<string>(1, m_attributeProfiles)));
209 for (indirect_iterator<vector<AttributeProfile*>::const_iterator> i = make_indirect_iterator(profiles->begin());
210 i != make_indirect_iterator(profiles->end()); ++i) {
211 auto_ptr_char temp(i->getProfileURI());
213 attr->getValues().push_back(temp.get());
215 if (attr->valueCount() > 0) {
216 attributes.push_back(attr.get());
222 if (!m_errorURL.empty() && roleToExtract->getErrorURL()) {
223 auto_ptr_char temp(roleToExtract->getErrorURL());
224 if (temp.get() && *temp.get()) {
225 auto_ptr<SimpleAttribute> attr(new SimpleAttribute(vector<string>(1, m_errorURL)));
226 attr->getValues().push_back(temp.get());
227 attributes.push_back(attr.get());
232 if (!m_displayName.empty() || !m_description.empty() || !m_informationURL.empty() || !m_privacyURL.empty()) {
233 const Extensions* exts = roleToExtract->getExtensions();
236 for (vector<XMLObject*>::const_iterator ext = exts->getUnknownXMLObjects().begin(); ext != exts->getUnknownXMLObjects().end(); ++ext) {
237 ui = dynamic_cast<const UIInfo*>(*ext);
239 doLangSensitive(request, ui->getDisplayNames(), m_displayName, attributes);
240 doLangSensitive(request, ui->getDescriptions(), m_description, attributes);
241 doLangSensitive(request, ui->getInformationURLs(), m_informationURL, attributes);
242 doLangSensitive(request, ui->getPrivacyStatementURLs(), m_privacyURL, attributes);
243 const vector<Logo*>& logos = ui->getLogos();
244 if (!logos.empty()) {
246 m_logos.begin(), m_logos.end(),
247 boost::bind(&MetadataExtractor::doLogo, this, request, boost::ref(logos), _1, boost::ref(attributes))
256 if (!m_orgName.empty() || !m_orgDisplayName.empty() || !m_orgURL.empty()) {
257 const Organization* org = roleToExtract->getOrganization();
259 org = dynamic_cast<EntityDescriptor*>(roleToExtract->getParent())->getOrganization();
261 doLangSensitive(request, org->getOrganizationNames(), m_orgName, attributes);
262 doLangSensitive(request, org->getOrganizationDisplayNames(), m_orgDisplayName, attributes);
263 doLangSensitive(request, org->getOrganizationURLs(), m_orgURL, attributes);
268 m_contacts.begin(), m_contacts.end(),
269 boost::bind(&MetadataExtractor::doContactPerson, this, roleToExtract, _1, boost::ref(attributes))
273 template <class T> void MetadataExtractor::doLangSensitive(
274 const GenericRequest* request, const vector<T*>& objects, const string& id, vector<shibsp::Attribute*>& attributes
277 if (objects.empty() || id.empty())
281 if (request && request->startLangMatching()) {
283 for (typename vector<T*>::const_iterator i = objects.begin(); !match && i != objects.end(); ++i) {
284 if (request->matchLang((*i)->getLang()))
287 } while (!match && request->continueLangMatching());
290 match = objects.front();
292 auto_ptr_char temp(match->getTextContent());
293 if (temp.get() && *temp.get()) {
294 auto_ptr<SimpleAttribute> attr(new SimpleAttribute(vector<string>(1, id)));
295 attr->getValues().push_back(temp.get());
296 attributes.push_back(attr.get());
301 void MetadataExtractor::doLogo(
302 const GenericRequest* request, const vector<Logo*>& logos, const logo_tuple_t& params, vector<shibsp::Attribute*>& attributes
309 Logo* match = nullptr;
310 int h = params.get<1>(), w = params.get<2>(), sizediff, bestdiff = INT_MAX;
311 if (request && request->startLangMatching()) {
313 for (vector<Logo*>::const_iterator i = logos.begin(); i != logos.end(); ++i) {
314 if (request->matchLang((*i)->getLang())) {
317 dim = (*i)->getHeight();
318 sizediff = abs(h - dim.second);
321 dim = (*i)->getWidth();
322 sizediff += abs(w - dim.second);
325 if (sizediff < bestdiff)
332 if (match && h == 0 && w == 0)
335 if (match && h == 0 && w == 0)
337 } while (request->continueLangMatching());
339 else if (h > 0 || w > 0) {
340 for (vector<Logo*>::const_iterator i = logos.begin(); i != logos.end(); ++i) {
343 dim = (*i)->getHeight();
344 sizediff = abs(h - dim.second);
347 dim = (*i)->getWidth();
348 sizediff += abs(w - dim.second);
351 if (sizediff < bestdiff)
360 match = logos.front();
363 if (!match->getDOM()) {
366 vector<string> ids(1, params.get<0>());
367 auto_ptr<Attribute> attr(params.get<3>()->decode(ids, match));
369 attributes.push_back(attr.get());
374 void MetadataExtractor::doContactPerson(
375 const RoleDescriptor* role, const contact_tuple_t& params, vector<shibsp::Attribute*>& attributes
378 const XMLCh* ctype = params.get<1>().c_str();
379 static bool (*eq)(const XMLCh*, const XMLCh*) = &XMLString::equals;
380 const ContactPerson* cp = find_if(role->getContactPersons(),boost::bind(eq, ctype, boost::bind(&ContactPerson::getContactType, _1)));
382 cp = find_if(dynamic_cast<EntityDescriptor*>(role->getParent())->getContactPersons(),
383 boost::bind(eq, ctype, boost::bind(&ContactPerson::getContactType, _1)));
390 vector<string> ids(1, params.get<0>());
391 auto_ptr<Attribute> attr(params.get<2>()->decode(ids, cp));
393 attributes.push_back(attr.get());