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 * shibsp/attribute/Attribute.cpp
23 *
24 * A resolved attribute.
25 */
26
27 #include "internal.h"
28 #include "exceptions.h"
29 #include "SPConfig.h"
30 #include "attribute/SimpleAttribute.h"
31 #ifndef SHIBSP_LITE
32 # include "attribute/AttributeDecoder.h"
33 #endif
34 #include "util/SPConstants.h"
35
36 #include <xmltooling/XMLObject.h>
37 #include <xmltooling/security/SecurityHelper.h>
38 #include <xmltooling/util/XMLHelper.h>
39 #include <xercesc/util/XMLUniDefs.hpp>
40
41 using namespace shibsp;
42 using namespace xmltooling;
43 using namespace std;
44
45 namespace shibsp {
46 SHIBSP_DLLLOCAL Attribute* SimpleAttributeFactory(DDF& in);
47 SHIBSP_DLLLOCAL Attribute* ScopedAttributeFactory(DDF& in);
48 SHIBSP_DLLLOCAL Attribute* NameIDAttributeFactory(DDF& in);
49 SHIBSP_DLLLOCAL Attribute* ExtensibleAttributeFactory(DDF& in);
50 SHIBSP_DLLLOCAL Attribute* XMLAttributeFactory(DDF& in);
51 SHIBSP_DLLLOCAL Attribute* BinaryAttributeFactory(DDF& in);
52
53 #ifndef SHIBSP_LITE
54 SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory StringAttributeDecoderFactory;
55 SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory ScopedAttributeDecoderFactory;
56 SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory NameIDAttributeDecoderFactory;
57 SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory NameIDFromScopedAttributeDecoderFactory;
58 SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory KeyInfoAttributeDecoderFactory;
59 SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory DOMAttributeDecoderFactory;
60 SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory XMLAttributeDecoderFactory;
61 SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory Base64AttributeDecoderFactory;
62
63 static const XMLCh _StringAttributeDecoder[] = UNICODE_LITERAL_22(S,t,r,i,n,g,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
64 static const XMLCh _ScopedAttributeDecoder[] = UNICODE_LITERAL_22(S,c,o,p,e,d,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
65 static const XMLCh _NameIDAttributeDecoder[] = UNICODE_LITERAL_22(N,a,m,e,I,D,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
66 static const XMLCh _NameIDFromScopedAttributeDecoder[] = UNICODE_LITERAL_32(N,a,m,e,I,D,F,r,o,m,S,c,o,p,e,d,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
67 static const XMLCh _KeyInfoAttributeDecoder[] =UNICODE_LITERAL_23(K,e,y,I,n,f,o,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
68 static const XMLCh _DOMAttributeDecoder[] = UNICODE_LITERAL_19(D,O,M,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
69 static const XMLCh _XMLAttributeDecoder[] = UNICODE_LITERAL_19(X,M,L,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
70 static const XMLCh _Base64AttributeDecoder[] = {
71 chLatin_B, chLatin_a, chLatin_s, chLatin_e, chDigit_6, chDigit_4,
72 chLatin_A, chLatin_t, chLatin_t, chLatin_r, chLatin_i, chLatin_b, chLatin_u, chLatin_t, chLatin_e,
73 chLatin_D, chLatin_e, chLatin_c, chLatin_o, chLatin_d, chLatin_e, chLatin_r, chNull
74 };
75
76 static const XMLCh hashAlg[] = UNICODE_LITERAL_7(h,a,s,h,A,l,g);
77 static const XMLCh internal[] = UNICODE_LITERAL_8(i,n,t,e,r,n,a,l);
78 static const XMLCh langAware[] = UNICODE_LITERAL_9(l,a,n,g,A,w,a,r,e);
79 #endif
80 };
81
82 #ifndef SHIBSP_LITE
83 xmltooling::QName shibsp::StringAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _StringAttributeDecoder);
84 xmltooling::QName shibsp::ScopedAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _ScopedAttributeDecoder);
85 xmltooling::QName shibsp::NameIDAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _NameIDAttributeDecoder);
86 xmltooling::QName shibsp::NameIDFromScopedAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _NameIDFromScopedAttributeDecoder);
87 xmltooling::QName shibsp::KeyInfoAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _KeyInfoAttributeDecoder);
88 xmltooling::QName shibsp::DOMAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _DOMAttributeDecoder);
89 xmltooling::QName shibsp::XMLAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _XMLAttributeDecoder);
90 xmltooling::QName shibsp::Base64AttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _Base64AttributeDecoder);
91
registerAttributeDecoders()92 void shibsp::registerAttributeDecoders()
93 {
94 SPConfig& conf = SPConfig::getConfig();
95 conf.AttributeDecoderManager.registerFactory(StringAttributeDecoderType, StringAttributeDecoderFactory);
96 conf.AttributeDecoderManager.registerFactory(ScopedAttributeDecoderType, ScopedAttributeDecoderFactory);
97 conf.AttributeDecoderManager.registerFactory(NameIDAttributeDecoderType, NameIDAttributeDecoderFactory);
98 conf.AttributeDecoderManager.registerFactory(NameIDFromScopedAttributeDecoderType, NameIDFromScopedAttributeDecoderFactory);
99 conf.AttributeDecoderManager.registerFactory(KeyInfoAttributeDecoderType, KeyInfoAttributeDecoderFactory);
100 conf.AttributeDecoderManager.registerFactory(DOMAttributeDecoderType, DOMAttributeDecoderFactory);
101 conf.AttributeDecoderManager.registerFactory(XMLAttributeDecoderType, XMLAttributeDecoderFactory);
102 conf.AttributeDecoderManager.registerFactory(Base64AttributeDecoderType, Base64AttributeDecoderFactory);
103 }
104
AttributeDecoder(const DOMElement * e)105 AttributeDecoder::AttributeDecoder(const DOMElement *e)
106 : m_caseSensitive(XMLHelper::getCaseSensitive(e, true)),
107 m_internal(XMLHelper::getAttrBool(e, false, internal)),
108 m_langAware(XMLHelper::getAttrBool(e, false, langAware)),
109 m_hashAlg(XMLHelper::getAttrString(e, nullptr, hashAlg))
110 {
111 if (m_internal) {
112 SPConfig::getConfig().deprecation().warn("<AttributeDecoder> internal option");
113 }
114 if (m_langAware) {
115 SPConfig::getConfig().deprecation().warn("<AttributeDecoder> langAware option");
116 }
117 if (!m_hashAlg.empty()) {
118 SPConfig::getConfig().deprecation().warn("<AttributeDecoder> hashAlg option");
119 }
120 }
121
~AttributeDecoder()122 AttributeDecoder::~AttributeDecoder()
123 {
124 }
125
_decode(Attribute * attr) const126 Attribute* AttributeDecoder::_decode(Attribute* attr) const
127 {
128 if (attr) {
129 attr->setCaseSensitive(m_caseSensitive);
130 attr->setInternal(m_internal);
131
132 if (!m_hashAlg.empty()) {
133 // We turn the values into strings using the supplied hash algorithm and return a SimpleAttribute instead.
134 auto_ptr<SimpleAttribute> simple(new SimpleAttribute(attr->getAliases()));
135 simple->setCaseSensitive(false);
136 simple->setInternal(m_internal);
137 vector<string>& newdest = simple->getValues();
138 const vector<string>& serialized = attr->getSerializedValues();
139 for (vector<string>::const_iterator ser = serialized.begin(); ser != serialized.end(); ++ser) {
140 newdest.push_back(SecurityHelper::doHash(m_hashAlg.c_str(), ser->data(), ser->length()));
141 if (newdest.back().empty())
142 newdest.pop_back();
143 }
144 delete attr;
145 return newdest.empty() ? nullptr : simple.release();
146 }
147
148 }
149 return attr;
150 }
151
valueRange(const GenericRequest * request,const vector<XMLObject * > & objects) const152 pair<vector<XMLObject*>::const_iterator,vector<XMLObject*>::const_iterator> AttributeDecoder::valueRange(
153 const GenericRequest* request, const vector<XMLObject*>& objects
154 ) const
155 {
156 if (!m_langAware || !request || objects.empty()) {
157 return make_pair(objects.begin(), objects.end());
158 }
159 else if (request && request->startLangMatching()) {
160 do {
161 for (vector<XMLObject*>::const_iterator i = objects.begin(); i != objects.end(); ++i) {
162 if (request->matchLang((*i)->getLang())) {
163 return make_pair(i, i + 1);
164 }
165 }
166 } while (request->continueLangMatching());
167 }
168
169 return make_pair(objects.begin(), objects.begin() + 1);
170 }
171 #endif
172
registerAttributeFactories()173 void shibsp::registerAttributeFactories()
174 {
175 Attribute::registerFactory("", SimpleAttributeFactory);
176 Attribute::registerFactory("Simple", SimpleAttributeFactory);
177 Attribute::registerFactory("Binary", BinaryAttributeFactory);
178 Attribute::registerFactory("Scoped", ScopedAttributeFactory);
179 Attribute::registerFactory("NameID", NameIDAttributeFactory);
180 Attribute::registerFactory("Extensible", ExtensibleAttributeFactory);
181 Attribute::registerFactory("XML", XMLAttributeFactory);
182 }
183
184 map<string,Attribute::AttributeFactory*> Attribute::m_factoryMap;
185
registerFactory(const char * type,AttributeFactory * factory)186 void Attribute::registerFactory(const char* type, AttributeFactory* factory)
187 {
188 m_factoryMap[type] = factory;
189 }
190
deregisterFactory(const char * type)191 void Attribute::deregisterFactory(const char* type)
192 {
193 m_factoryMap.erase(type);
194 }
195
deregisterFactories()196 void Attribute::deregisterFactories()
197 {
198 m_factoryMap.clear();
199 }
200
Attribute(const vector<string> & ids)201 Attribute::Attribute(const vector<string>& ids) : m_id(ids), m_caseSensitive(true), m_internal(false)
202 {
203 }
204
Attribute(DDF & in)205 Attribute::Attribute(DDF& in) : m_caseSensitive(in["case_insensitive"].isnull()), m_internal(!in["internal"].isnull())
206 {
207 const char* id = in.first().name();
208 if (id && *id)
209 m_id.push_back(id);
210 else
211 throw AttributeException("No id found in marshalled attribute content.");
212 DDF aliases = in["aliases"];
213 if (aliases.islist()) {
214 DDF alias = aliases.first();
215 while (alias.isstring()) {
216 m_id.push_back(alias.string());
217 alias = aliases.next();
218 }
219 }
220 }
221
~Attribute()222 Attribute::~Attribute()
223 {
224 }
225
getId() const226 const char* Attribute::getId() const
227 {
228 return m_id.front().c_str();
229 }
230
getAliases() const231 const vector<string>& Attribute::getAliases() const
232 {
233 return m_id;
234 }
235
getAliases()236 vector<string>& Attribute::getAliases()
237 {
238 return m_id;
239 }
240
setCaseSensitive(bool caseSensitive)241 void Attribute::setCaseSensitive(bool caseSensitive)
242 {
243 m_caseSensitive = caseSensitive;
244 }
245
setInternal(bool internal)246 void Attribute::setInternal(bool internal)
247 {
248 m_internal = internal;
249 }
250
isCaseSensitive() const251 bool Attribute::isCaseSensitive() const
252 {
253 return m_caseSensitive;
254 }
255
isInternal() const256 bool Attribute::isInternal() const
257 {
258 return m_internal;
259 }
260
valueCount() const261 size_t Attribute::valueCount() const
262 {
263 return m_serialized.size();
264 }
265
getSerializedValues() const266 const vector<string>& Attribute::getSerializedValues() const
267 {
268 return m_serialized;
269 }
270
getString(size_t index) const271 const char* Attribute::getString(size_t index) const
272 {
273 return m_serialized[index].c_str();
274 }
275
getScope(size_t index) const276 const char* Attribute::getScope(size_t index) const
277 {
278 return nullptr;
279 }
280
removeValue(size_t index)281 void Attribute::removeValue(size_t index)
282 {
283 if (index < m_serialized.size())
284 m_serialized.erase(m_serialized.begin() + index);
285 }
286
marshall() const287 DDF Attribute::marshall() const
288 {
289 DDF ddf(nullptr);
290 ddf.structure().addmember(m_id.front().c_str()).list();
291 if (!m_caseSensitive)
292 ddf.addmember("case_insensitive");
293 if (m_internal)
294 ddf.addmember("internal");
295 if (m_id.size() > 1) {
296 DDF alias;
297 DDF aliases = ddf.addmember("aliases").list();
298 for (std::vector<std::string>::const_iterator a = m_id.begin() + 1; a != m_id.end(); ++a) {
299 alias = DDF(nullptr).string(a->c_str());
300 aliases.add(alias);
301 }
302 }
303 return ddf;
304 }
305
unmarshall(DDF & in)306 Attribute* Attribute::unmarshall(DDF& in)
307 {
308 map<string,AttributeFactory*>::const_iterator i = m_factoryMap.find(in.name() ? in.name() : "");
309 if (i == m_factoryMap.end())
310 throw AttributeException("No registered factory for Attribute of type ($1).", params(1,in.name()));
311 return (i->second)(in);
312 }
313