https://bugs.internet2.edu/jira/browse/SSPCPP-365
[shibboleth/sp.git] / shibsp / attribute / Attribute.cpp
1 /*
2  *  Copyright 2001-2010 Internet2
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /**
18  * shibsp/attribute/Attribute.cpp
19  *
20  * A resolved attribute.
21  */
22
23 #include "internal.h"
24 #include "exceptions.h"
25 #include "SPConfig.h"
26 #ifndef SHIBSP_LITE
27 # include "attribute/AttributeDecoder.h"
28 #endif
29 #include "attribute/SimpleAttribute.h"
30 #include "attribute/ScopedAttribute.h"
31 #include "attribute/NameIDAttribute.h"
32 #include "attribute/ExtensibleAttribute.h"
33 #include "attribute/XMLAttribute.h"
34 #include "util/SPConstants.h"
35
36 #include <xercesc/util/XMLUniDefs.hpp>
37 #include <xmltooling/security/SecurityHelper.h>
38 #include <xmltooling/util/XMLHelper.h>
39
40 using namespace shibsp;
41 using namespace xmltooling;
42 using namespace std;
43
44 namespace shibsp {
45     SHIBSP_DLLLOCAL Attribute* SimpleAttributeFactory(DDF& in);
46     SHIBSP_DLLLOCAL Attribute* ScopedAttributeFactory(DDF& in);
47     SHIBSP_DLLLOCAL Attribute* NameIDAttributeFactory(DDF& in);
48     SHIBSP_DLLLOCAL Attribute* ExtensibleAttributeFactory(DDF& in);
49     SHIBSP_DLLLOCAL Attribute* XMLAttributeFactory(DDF& in);
50     SHIBSP_DLLLOCAL Attribute* BinaryAttributeFactory(DDF& in);
51
52 #ifndef SHIBSP_LITE
53     SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory StringAttributeDecoderFactory;
54     SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory ScopedAttributeDecoderFactory;
55     SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory NameIDAttributeDecoderFactory;
56     SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory NameIDFromScopedAttributeDecoderFactory;
57     SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory KeyInfoAttributeDecoderFactory;
58     SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory DOMAttributeDecoderFactory;
59     SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory XMLAttributeDecoderFactory;
60     SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory Base64AttributeDecoderFactory;
61
62     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);
63     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);
64     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);
65     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);
66     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);
67     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);
68     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);
69     static const XMLCh _Base64AttributeDecoder[] = {
70         chLatin_B, chLatin_a, chLatin_s, chLatin_e, chDigit_6, chDigit_4,
71         chLatin_A, chLatin_t, chLatin_t, chLatin_r, chLatin_i, chLatin_b, chLatin_u, chLatin_t, chLatin_e,
72         chLatin_D, chLatin_e, chLatin_c, chLatin_o, chLatin_d, chLatin_e, chLatin_r, chNull
73     };
74
75     static const XMLCh caseSensitive[] =           UNICODE_LITERAL_13(c,a,s,e,S,e,n,s,i,t,i,v,e);
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 #endif
79 };
80
81 #ifndef SHIBSP_LITE
82 xmltooling::QName shibsp::StringAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _StringAttributeDecoder);
83 xmltooling::QName shibsp::ScopedAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _ScopedAttributeDecoder);
84 xmltooling::QName shibsp::NameIDAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _NameIDAttributeDecoder);
85 xmltooling::QName shibsp::NameIDFromScopedAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _NameIDFromScopedAttributeDecoder);
86 xmltooling::QName shibsp::KeyInfoAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _KeyInfoAttributeDecoder);
87 xmltooling::QName shibsp::DOMAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _DOMAttributeDecoder);
88 xmltooling::QName shibsp::XMLAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _XMLAttributeDecoder);
89 xmltooling::QName shibsp::Base64AttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _Base64AttributeDecoder);
90
91 void shibsp::registerAttributeDecoders()
92 {
93     SPConfig& conf = SPConfig::getConfig();
94     conf.AttributeDecoderManager.registerFactory(StringAttributeDecoderType, StringAttributeDecoderFactory);
95     conf.AttributeDecoderManager.registerFactory(ScopedAttributeDecoderType, ScopedAttributeDecoderFactory);
96     conf.AttributeDecoderManager.registerFactory(NameIDAttributeDecoderType, NameIDAttributeDecoderFactory);
97     conf.AttributeDecoderManager.registerFactory(NameIDFromScopedAttributeDecoderType, NameIDFromScopedAttributeDecoderFactory);
98     conf.AttributeDecoderManager.registerFactory(KeyInfoAttributeDecoderType, KeyInfoAttributeDecoderFactory);
99     conf.AttributeDecoderManager.registerFactory(DOMAttributeDecoderType, DOMAttributeDecoderFactory);
100     conf.AttributeDecoderManager.registerFactory(XMLAttributeDecoderType, XMLAttributeDecoderFactory);
101     conf.AttributeDecoderManager.registerFactory(Base64AttributeDecoderType, Base64AttributeDecoderFactory);
102 }
103
104 AttributeDecoder::AttributeDecoder(const DOMElement *e)
105     : m_caseSensitive(XMLHelper::getAttrBool(e, true, caseSensitive)),
106         m_internal(XMLHelper::getAttrBool(e, false, internal)),
107         m_hashAlg(XMLHelper::getAttrString(e, nullptr, hashAlg))
108 {
109 }
110
111 AttributeDecoder::~AttributeDecoder()
112 {
113 }
114
115 Attribute* AttributeDecoder::_decode(Attribute* attr) const
116 {
117     if (attr) {
118         attr->setCaseSensitive(m_caseSensitive);
119         attr->setInternal(m_internal);
120
121         if (!m_hashAlg.empty()) {
122             // We turn the values into strings using the supplied hash algorithm and return a SimpleAttribute instead.
123             auto_ptr<SimpleAttribute> simple(new SimpleAttribute(attr->getAliases()));
124             simple->setCaseSensitive(false);
125             simple->setInternal(m_internal);
126             vector<string>& newdest = simple->getValues();
127             const vector<string>& serialized = attr->getSerializedValues();
128             for (vector<string>::const_iterator ser = serialized.begin(); ser != serialized.end(); ++ser) {
129                 newdest.push_back(SecurityHelper::doHash(m_hashAlg.c_str(), ser->data(), ser->length()));
130                 if (newdest.back().empty())
131                     newdest.pop_back();
132             }
133             delete attr;
134             return newdest.empty() ? nullptr : simple.release();
135         }
136
137     }
138     return attr;
139 }
140 #endif
141
142 void shibsp::registerAttributeFactories()
143 {
144     Attribute::registerFactory("", SimpleAttributeFactory);
145     Attribute::registerFactory("Simple", SimpleAttributeFactory);
146     Attribute::registerFactory("Binary", BinaryAttributeFactory);
147     Attribute::registerFactory("Scoped", ScopedAttributeFactory);
148     Attribute::registerFactory("NameID", NameIDAttributeFactory);
149     Attribute::registerFactory("Extensible", ExtensibleAttributeFactory);
150     Attribute::registerFactory("XML", XMLAttributeFactory);
151 }
152
153 map<string,Attribute::AttributeFactory*> Attribute::m_factoryMap;
154
155 void Attribute::registerFactory(const char* type, AttributeFactory* factory)
156 {
157     m_factoryMap[type] = factory;
158 }
159
160 void Attribute::deregisterFactory(const char* type)
161 {
162     m_factoryMap.erase(type);
163 }
164
165 void Attribute::deregisterFactories()
166 {
167     m_factoryMap.clear();
168 }
169
170 Attribute::Attribute(const vector<string>& ids) : m_id(ids), m_caseSensitive(true), m_internal(false)
171 {
172 }
173
174 Attribute::Attribute(DDF& in) : m_caseSensitive(in["case_insensitive"].isnull()), m_internal(!in["internal"].isnull())
175 {
176     const char* id = in.first().name();
177     if (id && *id)
178         m_id.push_back(id);
179     else
180         throw AttributeException("No id found in marshalled attribute content.");
181     DDF aliases = in["aliases"];
182     if (aliases.islist()) {
183         DDF alias = aliases.first();
184         while (alias.isstring()) {
185             m_id.push_back(alias.string());
186             alias = aliases.next();
187         }
188     }
189 }
190
191 Attribute::~Attribute()
192 {
193 }
194
195 const char* Attribute::getId() const
196 {
197     return m_id.front().c_str();
198 }
199
200 const vector<string>& Attribute::getAliases() const
201 {
202     return m_id;
203 }
204
205 vector<string>& Attribute::getAliases()
206 {
207     return m_id;
208 }
209
210 void Attribute::setCaseSensitive(bool caseSensitive)
211 {
212     m_caseSensitive = caseSensitive;
213 }
214
215 void Attribute::setInternal(bool internal)
216 {
217     m_internal = internal;
218 }
219
220 bool Attribute::isCaseSensitive() const
221 {
222     return m_caseSensitive;
223 }
224
225 bool Attribute::isInternal() const
226 {
227     return m_internal;
228 }
229
230 size_t Attribute::valueCount() const
231 {
232     return m_serialized.size();
233 }
234
235 const vector<string>& Attribute::getSerializedValues() const
236 {
237     return m_serialized;
238 }
239
240 const char* Attribute::getString(size_t index) const
241 {
242     return m_serialized[index].c_str();
243 }
244
245 const char* Attribute::getScope(size_t index) const
246 {
247     return nullptr;
248 }
249
250 void Attribute::removeValue(size_t index)
251 {
252     if (index < m_serialized.size())
253         m_serialized.erase(m_serialized.begin() + index);
254 }
255
256 DDF Attribute::marshall() const
257 {
258     DDF ddf(nullptr);
259     ddf.structure().addmember(m_id.front().c_str()).list();
260     if (!m_caseSensitive)
261         ddf.addmember("case_insensitive");
262     if (m_internal)
263         ddf.addmember("internal");
264     if (m_id.size() > 1) {
265         DDF alias;
266         DDF aliases = ddf.addmember("aliases").list();
267         for (std::vector<std::string>::const_iterator a = m_id.begin() + 1; a != m_id.end(); ++a) {
268             alias = DDF(nullptr).string(a->c_str());
269             aliases.add(alias);
270         }
271     }
272     return ddf;
273 }
274
275 Attribute* Attribute::unmarshall(DDF& in)
276 {
277     map<string,AttributeFactory*>::const_iterator i = m_factoryMap.find(in.name() ? in.name() : "");
278     if (i == m_factoryMap.end())
279         throw AttributeException("No registered factory for Attribute of type ($1).", params(1,in.name()));
280     return (i->second)(in);
281 }