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 * DOMPropertySet.cpp
23 *
24 * DOM-based property set implementation.
25 */
26
27 #include "internal.h"
28 #include "util/DOMPropertySet.h"
29
30 #include <algorithm>
31 #include <boost/lexical_cast.hpp>
32 #include <boost/algorithm/string.hpp>
33 #include <xmltooling/util/NDC.h>
34 #include <xmltooling/util/XMLConstants.h>
35 #include <xmltooling/util/XMLHelper.h>
36
37 using namespace shibsp;
38 using namespace xmltooling;
39 using namespace xercesc;
40 using namespace boost;
41 using namespace std;
42
PropertySet()43 PropertySet::PropertySet()
44 {
45 }
46
~PropertySet()47 PropertySet::~PropertySet()
48 {
49 }
50
Remapper()51 DOMPropertySet::Remapper::Remapper()
52 {
53 }
54
~Remapper()55 DOMPropertySet::Remapper::~Remapper()
56 {
57 }
58
STLRemapper(const std::map<std::string,std::string> & rules)59 DOMPropertySet::STLRemapper::STLRemapper(const std::map<std::string, std::string>& rules) : m_rules(rules)
60 {
61 }
62
~STLRemapper()63 DOMPropertySet::STLRemapper::~STLRemapper()
64 {
65 }
66
remap(const char * src,xmltooling::logging::Category & log) const67 const char* DOMPropertySet::STLRemapper::remap(const char* src, xmltooling::logging::Category& log) const
68 {
69 map<string,string>::const_iterator i = src ? m_rules.find(src) : m_rules.end();
70 if (i != m_rules.end()) {
71 SPConfig::getConfig().deprecation().warn("legacy configuration, remapping property/set (%s) to (%s)", src, i->second.c_str());
72 return i->second.c_str();
73 }
74 else {
75 return src;
76 }
77 }
78
DOMPropertySet()79 DOMPropertySet::DOMPropertySet() : m_parent(nullptr), m_root(nullptr)
80 {
81 }
82
~DOMPropertySet()83 DOMPropertySet::~DOMPropertySet()
84 {
85 for (map<string,pair<char*,const XMLCh*> >::iterator i = m_map.begin(); i != m_map.end(); ++i)
86 XMLString::release(&(i->second.first));
87 }
88
getParent() const89 const PropertySet* DOMPropertySet::getParent() const
90 {
91 return m_parent;
92 }
93
setParent(const PropertySet * parent)94 void DOMPropertySet::setParent(const PropertySet* parent)
95 {
96 m_parent = parent;
97 }
98
getElement() const99 const DOMElement* DOMPropertySet::getElement() const
100 {
101 return m_root;
102 }
103
load(const DOMElement * e,Category * log,DOMNodeFilter * filter,const Remapper * remapper,const xmltooling::QName * unsetter)104 void DOMPropertySet::load(
105 const DOMElement* e,
106 Category* log,
107 DOMNodeFilter* filter,
108 const Remapper* remapper,
109 const xmltooling::QName* unsetter
110 )
111 {
112 #ifdef _DEBUG
113 NDC ndc("load");
114 #endif
115 if (!e)
116 return;
117 m_root=e;
118 if (!log)
119 log = &Category::getInstance(SHIBSP_LOGCAT ".PropertySet");
120
121 // Process each attribute as a property.
122 DOMNamedNodeMap* attrs=m_root->getAttributes();
123 for (XMLSize_t i=0; i<attrs->getLength(); i++) {
124 DOMNode* a=attrs->item(i);
125 if (!XMLString::compareString(a->getNamespaceURI(), xmlconstants::XMLNS_NS)) {
126 continue;
127 }
128 else if (unsetter && XMLHelper::isNodeNamed(a, unsetter->getNamespaceURI(), unsetter->getLocalPart())) {
129 auto_ptr_char val(a->getNodeValue());
130 string dup(val.get());
131 split(m_unset, dup, is_space(), algorithm::token_compress_on);
132 continue;
133 }
134
135 char* val=XMLString::transcode(a->getNodeValue());
136 if (val && *val) {
137 auto_ptr_char ns(a->getNamespaceURI());
138 auto_ptr_char name(a->getLocalName());
139 const char* realname=name.get();
140 if (remapper) {
141 realname = remapper->remap(realname, *log);
142 }
143 if (ns.get()) {
144 const char* realns = ns.get();
145 if (remapper) {
146 realns = remapper->remap(realns, *log);
147 }
148 else if (XMLString::equals(realns, shibspconstants::ASCII_SHIB2SPCONFIG_NS)) {
149 realns = shibspconstants::ASCII_SHIB3SPCONFIG_NS;
150 }
151 m_map[string("{") + realns + '}' + realname] = pair<char*, const XMLCh*>(val, a->getNodeValue());
152 log->debug("added property {%s}%s (%s)", realns, realname, val);
153 }
154 else {
155 m_map[realname]=pair<char*,const XMLCh*>(val,a->getNodeValue());
156 log->debug("added property %s (%s)", realname, val);
157 }
158 }
159 }
160
161 // Process non-excluded elements as nested sets.
162 DOMTreeWalker* walker =
163 static_cast<DOMDocumentTraversal*>(
164 m_root->getOwnerDocument())->createTreeWalker(const_cast<DOMElement*>(m_root),DOMNodeFilter::SHOW_ELEMENT,filter,false
165 );
166 e = static_cast<DOMElement*>(walker->firstChild());
167 while (e) {
168 auto_ptr_char ns(e->getNamespaceURI());
169 auto_ptr_char name(e->getLocalName());
170 const char* realname=name.get();
171 if (remapper) {
172 realname = remapper->remap(realname, *log);
173 }
174 string key;
175 if (ns.get()) {
176 const char* realns = ns.get();
177 if (remapper) {
178 realns = remapper->remap(realns, *log);
179 }
180 else if (XMLString::equals(realns, shibspconstants::ASCII_SHIB2SPCONFIG_NS)) {
181 realns = shibspconstants::ASCII_SHIB3SPCONFIG_NS;
182 }
183 key = string("{") + realns + '}' + realname;
184 }
185 else {
186 key = realname;
187 }
188 if (m_nested.find(key) != m_nested.end())
189 log->warn("load() skipping duplicate property set: %s", key.c_str());
190 else {
191 boost::shared_ptr<DOMPropertySet> newset(new DOMPropertySet());
192 newset->load(e,log,filter,remapper);
193 m_nested[key] = newset;
194 log->debug("added nested property set: %s", key.c_str());
195 }
196 e = static_cast<DOMElement*>(walker->nextSibling());
197 }
198 walker->release();
199 }
200
getBool(const char * name,const char * ns) const201 pair<bool,bool> DOMPropertySet::getBool(const char* name, const char* ns) const
202 {
203 map< string,pair<char*,const XMLCh*> >::const_iterator i;
204
205 if (ns)
206 i=m_map.find(string("{") + ns + '}' + name);
207 else
208 i=m_map.find(name);
209
210
211 if (i!=m_map.end())
212 return make_pair(true,(!strcmp(i->second.first,"true") || !strcmp(i->second.first,"1")));
213 else if (m_parent && m_unset.find(ns ? (string("{") + ns + '}' + name) : name) == m_unset.end()) {
214 return m_parent->getBool(name, ns);
215 }
216 return make_pair(false,false);
217 }
218
getString(const char * name,const char * ns) const219 pair<bool,const char*> DOMPropertySet::getString(const char* name, const char* ns) const
220 {
221 map< string,pair<char*,const XMLCh*> >::const_iterator i;
222
223 if (ns)
224 i=m_map.find(string("{") + ns + '}' + name);
225 else
226 i=m_map.find(name);
227
228 if (i!=m_map.end())
229 return pair<bool,const char*>(true,i->second.first);
230 else if (m_parent && m_unset.find(ns ? (string("{") + ns + '}' + name) : name) == m_unset.end())
231 return m_parent->getString(name,ns);
232 return pair<bool,const char*>(false,nullptr);
233 }
234
getXMLString(const char * name,const char * ns) const235 pair<bool,const XMLCh*> DOMPropertySet::getXMLString(const char* name, const char* ns) const
236 {
237 map< string,pair<char*,const XMLCh*> >::const_iterator i;
238
239 if (ns)
240 i=m_map.find(string("{") + ns + '}' + name);
241 else
242 i=m_map.find(name);
243
244 if (i!=m_map.end())
245 return make_pair(true,i->second.second);
246 else if (m_parent && m_unset.find(ns ? (string("{") + ns + '}' + name) : name) == m_unset.end())
247 return m_parent->getXMLString(name,ns);
248 return pair<bool,const XMLCh*>(false,nullptr);
249 }
250
getUnsignedInt(const char * name,const char * ns) const251 pair<bool,unsigned int> DOMPropertySet::getUnsignedInt(const char* name, const char* ns) const
252 {
253 map< string,pair<char*,const XMLCh*> >::const_iterator i;
254
255 if (ns)
256 i=m_map.find(string("{") + ns + '}' + name);
257 else
258 i=m_map.find(name);
259
260 if (i!=m_map.end()) {
261 try {
262 return pair<bool,unsigned int>(true,lexical_cast<unsigned int>(i->second.first));
263 }
264 catch (bad_lexical_cast&) {
265 return pair<bool,unsigned int>(false,0);
266 }
267 }
268 else if (m_parent && m_unset.find(ns ? (string("{") + ns + '}' + name) : name) == m_unset.end())
269 return m_parent->getUnsignedInt(name,ns);
270 return pair<bool,unsigned int>(false,0);
271 }
272
getInt(const char * name,const char * ns) const273 pair<bool,int> DOMPropertySet::getInt(const char* name, const char* ns) const
274 {
275 map< string,pair<char*,const XMLCh*> >::const_iterator i;
276
277 if (ns)
278 i=m_map.find(string("{") + ns + '}' + name);
279 else
280 i=m_map.find(name);
281
282 if (i!=m_map.end())
283 return pair<bool,int>(true,atoi(i->second.first));
284 else if (m_parent && m_unset.find(ns ? (string("{") + ns + '}' + name) : name) == m_unset.end())
285 return m_parent->getInt(name,ns);
286 return pair<bool,int>(false,0);
287 }
288
getPropertySet(const char * name,const char * ns) const289 const PropertySet* DOMPropertySet::getPropertySet(const char* name, const char* ns) const
290 {
291 map< string,boost::shared_ptr<DOMPropertySet> >::const_iterator i;
292
293 if (ns)
294 i = m_nested.find(string("{") + ns + '}' + name);
295 else
296 i = m_nested.find(name);
297
298 return (i != m_nested.end()) ? i->second.get() : (m_parent ? m_parent->getPropertySet(name,ns) : nullptr);
299 }
300
setProperty(const char * name,const char * val,const char * ns)301 bool DOMPropertySet::setProperty(const char* name, const char* val, const char* ns)
302 {
303 string propname = ns ? (string("{") + ns + "}" + name) : name;
304
305 // Erase existing property.
306 if (m_map.count(propname) > 0) {
307 XMLString::release(&m_map[propname].first);
308 m_map.erase(propname);
309 }
310
311 char* dup = XMLString::replicate(val);
312 auto_ptr_XMLCh widedup(val);
313 m_injected.push_back(widedup.get());
314 m_map[propname] = make_pair(dup, m_injected.back().c_str());
315
316 return true;
317 }
318