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