SSPCPP-616 - clean up concatenated string literals
[shibboleth/cpp-opensaml.git] / saml / saml2 / metadata / impl / EntityAttributesMetadataFilter.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  * EntityAttributesMetadataFilter.cpp
23  *
24  * Adds EntityAttributes tags to entities.
25  */
26
27 #include "internal.h"
28 #include "saml2/metadata/Metadata.h"
29 #include "saml2/metadata/MetadataFilter.h"
30
31 #include <boost/lambda/bind.hpp>
32 #include <boost/lambda/casts.hpp>
33 #include <boost/lambda/lambda.hpp>
34 #include <boost/shared_ptr.hpp>
35 #include <boost/iterator/indirect_iterator.hpp>
36 #include <xmltooling/logging.h>
37
38 using namespace opensaml::saml2;
39 using namespace opensaml::saml2md;
40 using namespace xmltooling::logging;
41 using namespace xmltooling;
42 using namespace boost::lambda;
43 using namespace boost;
44 using namespace std;
45
46 namespace opensaml {
47     namespace saml2md {
48
49         class SAML_DLLLOCAL EntityAttributesMetadataFilter : public MetadataFilter
50         {
51         public:
52             EntityAttributesMetadataFilter(const DOMElement* e);
53             ~EntityAttributesMetadataFilter() {}
54
55             const char* getId() const { return ENTITYATTR_METADATA_FILTER; }
56             void doFilter(XMLObject& xmlObject) const;
57
58         private:
59             void filterEntity(EntityDescriptor* entity) const;
60             void filterGroup(EntitiesDescriptor* entities) const;
61
62             vector< boost::shared_ptr<Attribute> > m_attributes;
63             typedef multimap<xstring,const Attribute*> applymap_t;
64             applymap_t m_applyMap;
65         };
66
67         MetadataFilter* SAML_DLLLOCAL EntityAttributesMetadataFilterFactory(const DOMElement* const & e)
68         {
69             return new EntityAttributesMetadataFilter(e);
70         }
71
72         static const XMLCh Entity[] =   UNICODE_LITERAL_6(E,n,t,i,t,y);
73
74     };
75 };
76
77
78 EntityAttributesMetadataFilter::EntityAttributesMetadataFilter(const DOMElement* e)
79 {
80     // Contains ordered set of Attribute and Entity elements.
81     // We track each Attribute we find, and then consume an Entity by adding.
82     // a mapping from the Entity to every Attribute seen to that point.
83     DOMElement* child = XMLHelper::getFirstChildElement(e);
84     while (child) {
85         if (XMLHelper::isNodeNamed(child, samlconstants::SAML20_NS, Attribute::LOCAL_NAME)) {
86             boost::shared_ptr<XMLObject> obj(AttributeBuilder::buildOneFromElement(child));
87             m_attributes.push_back(boost::dynamic_pointer_cast<Attribute>(obj));
88         }
89         else if (XMLString::equals(child->getLocalName(), Entity)) {
90             const XMLCh* eid = child->getTextContent();
91             if (eid && *eid) {
92                 for (vector< boost::shared_ptr<Attribute> >::const_iterator a = m_attributes.begin(); a != m_attributes.end(); ++a)
93                     m_applyMap.insert(applymap_t::value_type(eid, a->get()));
94             }
95         }
96         child = XMLHelper::getNextSiblingElement(child);
97     }
98 }
99
100 void EntityAttributesMetadataFilter::doFilter(XMLObject& xmlObject) const
101 {
102     EntitiesDescriptor* group = dynamic_cast<EntitiesDescriptor*>(&xmlObject);
103     if (group) {
104         filterGroup(group);
105     }
106     else {
107         EntityDescriptor* entity = dynamic_cast<EntityDescriptor*>(&xmlObject);
108         if (entity) {
109             filterEntity(entity);
110         }
111         else {
112             throw MetadataFilterException(ENTITYATTR_METADATA_FILTER " MetadataFilter was given an improper metadata instance to filter.");
113         }
114     }
115 }
116
117 void EntityAttributesMetadataFilter::filterGroup(EntitiesDescriptor* entities) const
118 {
119     const vector<EntityDescriptor*>& v = const_cast<const EntitiesDescriptor*>(entities)->getEntityDescriptors();
120     for_each(v.begin(), v.end(), lambda::bind(&EntityAttributesMetadataFilter::filterEntity, this, _1));
121
122     const vector<EntitiesDescriptor*>& v2 = const_cast<const EntitiesDescriptor*>(entities)->getEntitiesDescriptors();
123     for_each(v2.begin(), v2.end(), lambda::bind(&EntityAttributesMetadataFilter::filterGroup, this, _1));
124 }
125
126 void EntityAttributesMetadataFilter::filterEntity(EntityDescriptor* entity) const
127 {
128     if (entity->getEntityID()) {
129         pair<applymap_t::const_iterator,applymap_t::const_iterator> tags = m_applyMap.equal_range(entity->getEntityID());
130         if (tags.first != tags.second) {
131             Extensions* exts = entity->getExtensions();
132             if (!exts) {
133                 entity->setExtensions(ExtensionsBuilder::buildExtensions());
134                 exts = entity->getExtensions();
135             }
136             EntityAttributes* wrapper = nullptr;
137             const vector<XMLObject*>& children = const_cast<const Extensions*>(exts)->getUnknownXMLObjects();
138             XMLObject* xo = find_if(children, ll_dynamic_cast<EntityAttributes*>(_1) != ((EntityAttributes*)nullptr));
139             if (xo) {
140                 wrapper = dynamic_cast<EntityAttributes*>(xo);
141             }
142             else {
143                 wrapper = EntityAttributesBuilder::buildEntityAttributes();
144                 exts->getUnknownXMLObjects().push_back(wrapper);
145             }
146             VectorOf(Attribute) attrs = wrapper->getAttributes();
147             for (; tags.first != tags.second; ++tags.first) {
148                 auto_ptr<Attribute> np(tags.first->second->cloneAttribute());
149                 attrs.push_back(np.get());
150                 np.release();
151             }
152         }
153     }
154 }