407fd81d2765333743f4c4a6dc98e3a430d4f0f6
[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::shared_dynamic_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(
121         make_indirect_iterator(v.begin()), make_indirect_iterator(v.end()),
122         lambda::bind(&EntityAttributesMetadataFilter::filterEntity, this, _1)
123         );
124
125     const vector<EntitiesDescriptor*>& v2 = const_cast<const EntitiesDescriptor&>(entities).getEntitiesDescriptors();
126     for_each(
127         make_indirect_iterator(v2.begin()), make_indirect_iterator(v2.end()),
128         lambda::bind(&EntityAttributesMetadataFilter::filterGroup, this, _1)
129         );
130 }
131
132 void EntityAttributesMetadataFilter::filterEntity(EntityDescriptor& entity) const
133 {
134     if (entity.getEntityID()) {
135         pair<applymap_t::const_iterator,applymap_t::const_iterator> tags = m_applyMap.equal_range(entity.getEntityID());
136         if (tags.first != tags.second) {
137             Extensions* exts = entity.getExtensions();
138             if (!exts) {
139                 entity.setExtensions(ExtensionsBuilder::buildExtensions());
140                 exts = entity.getExtensions();
141             }
142             EntityAttributes* wrapper = nullptr;
143             const vector<XMLObject*>& children = const_cast<const Extensions*>(exts)->getUnknownXMLObjects();
144             XMLObject* xo = find_if(children, ll_dynamic_cast<EntityAttributes*>(_1) != ((EntityAttributes*)nullptr));
145             if (xo) {
146                 wrapper = dynamic_cast<EntityAttributes*>(xo);
147             }
148             else {
149                 wrapper = EntityAttributesBuilder::buildEntityAttributes();
150                 exts->getUnknownXMLObjects().push_back(wrapper);
151             }
152             VectorOf(Attribute) attrs = wrapper->getAttributes();
153             for (; tags.first != tags.second; ++tags.first) {
154                 auto_ptr<Attribute> np(tags.first->second->cloneAttribute());
155                 attrs.push_back(np.get());
156                 np.release();
157             }
158         }
159     }
160 }