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