2 * The Shibboleth License, Version 1.
4 * University Corporation for Advanced Internet Development, Inc.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
11 * Redistributions of source code must retain the above copyright notice, this
12 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution, if any, must include
17 * the following acknowledgment: "This product includes software developed by
18 * the University Corporation for Advanced Internet Development
19 * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement
20 * may appear in the software itself, if and wherever such third-party
21 * acknowledgments normally appear.
23 * Neither the name of Shibboleth nor the names of its contributors, nor
24 * Internet2, nor the University Corporation for Advanced Internet Development,
25 * Inc., nor UCAID may be used to endorse or promote products derived from this
26 * software without specific prior written permission. For written permission,
27 * please contact shibboleth@shibboleth.org
29 * Products derived from this software may not be called Shibboleth, Internet2,
30 * UCAID, or the University Corporation for Advanced Internet Development, nor
31 * may Shibboleth appear in their name, without prior written permission of the
32 * University Corporation for Advanced Internet Development.
35 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
36 * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
38 * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK
39 * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE.
40 * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY
41 * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT,
42 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
43 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
44 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
47 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51 /* TargetedID.cpp - eduPersonTargetedID custom attribute handling
60 #include <xercesc/util/Base64.hpp>
62 using namespace shibboleth;
67 class TargetedID : public SAMLAttribute
71 const XMLCh* name=NULL,
73 const saml::QName* type=NULL,
75 const Iterator<const XMLCh*>& values=EMPTY(const XMLCh*),
76 const Iterator<const XMLCh*>& nameQualifiers=EMPTY(const XMLCh*),
77 const Iterator<const XMLCh*>& spNameQualifiers=EMPTY(const XMLCh*)
79 TargetedID(DOMElement* e);
80 TargetedID(istream& in);
83 saml::SAMLObject* clone() const;
85 saml::Iterator<const XMLCh*> getValues() const;
86 saml::Iterator<std::string> getSingleByteValues() const;
88 void setValues(const saml::Iterator<const XMLCh*>& values=EMPTY(const XMLCh*)) {
89 throw SAMLException("unsupported operation");
91 void addValue(const XMLCh* value) {
92 throw SAMLException("unsupported operation");
94 void removeValue(unsigned int index);
96 static const XMLCh NameID[];
97 static const XMLCh SPNameQualifier[];
98 static const XMLCh FORMAT_PERSISTENT[];
100 void valueToDOM(unsigned int index, DOMElement* e) const;
101 void valueFromDOM(DOMElement* e);
105 vector<const XMLCh*> m_nameQualifiers;
106 vector<const XMLCh*> m_spNameQualifiers;
107 mutable vector<const XMLCh*> m_encodedValues;
110 struct TargetedIDBuilder : public virtual IAttributeFactory
112 TargetedIDBuilder(const DOMElement* e) {}
113 SAMLAttribute* build(DOMElement* e) const {
114 return new TargetedID(e);
119 IPlugIn* TargetedIDFactory(const DOMElement* e)
121 return new TargetedIDBuilder(e);
124 TargetedID::TargetedID(
127 const saml::QName* type,
129 const Iterator<const XMLCh*>& values,
130 const Iterator<const XMLCh*>& nameQualifiers,
131 const Iterator<const XMLCh*>& spNameQualifiers
132 ) : SAMLAttribute(name,ns,NULL,lifetime,values)
135 if (values.size()!=nameQualifiers.size() || values.size()!=spNameQualifiers.size())
136 throw MalformedException("TargetedID() requires the number of qualifiers to equal the number of values");
138 while (nameQualifiers.hasNext())
139 m_nameQualifiers.push_back(saml::XML::assign(nameQualifiers.next()));
140 while (spNameQualifiers.hasNext())
141 m_spNameQualifiers.push_back(saml::XML::assign(spNameQualifiers.next()));
144 TargetedID::TargetedID(DOMElement* e) : SAMLAttribute(e,false)
150 TargetedID::TargetedID(istream& in) : SAMLAttribute(in,false)
153 fromDOM(m_document->getDocumentElement());
156 TargetedID::~TargetedID()
159 for (vector<const XMLCh*>::iterator i=m_nameQualifiers.begin(); i!=m_nameQualifiers.end(); i++) {
160 XMLCh* p = const_cast<XMLCh*>(*i);
161 XMLString::release(&p);
163 for (vector<const XMLCh*>::iterator j=m_spNameQualifiers.begin(); j!=m_spNameQualifiers.end(); j++) {
164 XMLCh* p = const_cast<XMLCh*>(*j);
165 XMLString::release(&p);
169 // We always own any encoded values we've built.
170 for (vector<const XMLCh*>::iterator i=m_encodedValues.begin(); i!=m_encodedValues.end(); i++) {
171 XMLCh* p = const_cast<XMLCh*>(*i);
172 XMLString::release(&p);
176 void TargetedID::ownStrings()
178 if (!m_bOwnStrings) {
179 for (vector<const XMLCh*>::iterator i=m_nameQualifiers.begin(); i!=m_nameQualifiers.end(); i++)
180 (*i)=saml::XML::assign(*i);
181 for (vector<const XMLCh*>::iterator j=m_spNameQualifiers.begin(); j!=m_spNameQualifiers.end(); j++)
182 (*j)=saml::XML::assign(*j);
183 SAMLAttribute::ownStrings();
187 Iterator<const XMLCh*> TargetedID::getValues() const
189 if (m_encodedValues.empty()) {
190 getSingleByteValues();
191 for (vector<string>::const_iterator i=m_sbValues.begin(); i!=m_sbValues.end(); i++)
192 m_encodedValues.push_back(XMLString::transcode(i->c_str()));
194 return m_encodedValues;
197 Iterator<string> TargetedID::getSingleByteValues() const
199 if (m_sbValues.empty()) {
200 for (unsigned long i=0; i<m_values.size(); i++) {
201 auto_ptr_char a(m_nameQualifiers[i]);
202 auto_ptr_char b(m_spNameQualifiers[i]);
203 auto_ptr_char c(m_values[i]);
204 if (a.get() && *(a.get()) && b.get() && *(b.get()) && c.get() && *(c.get())) {
205 string cat(a.get()); cat+="!!"; cat+=b.get(); cat+="!!"; cat+=c.get();
207 XMLByte* encoded = Base64::encode(reinterpret_cast<XMLByte*>((char*)cat.c_str()), cat.length(), &outlen);
209 for (pos=encoded, pos2=encoded; *pos2; pos2++)
213 m_sbValues.push_back(reinterpret_cast<char*>(encoded));
214 XMLString::release(&encoded);
217 m_sbValues.push_back("");
223 void TargetedID::removeValue(unsigned int index)
226 XMLCh* p=const_cast<XMLCh*>(m_nameQualifiers[index]);
227 XMLString::release(&p);
228 p=const_cast<XMLCh*>(m_spNameQualifiers[index]);
229 XMLString::release(&p);
231 m_nameQualifiers.erase(m_nameQualifiers.begin()+index);
232 m_spNameQualifiers.erase(m_spNameQualifiers.begin()+index);
234 if (!m_encodedValues.empty()) {
235 XMLCh* p=const_cast<XMLCh*>(m_encodedValues[index]);
236 XMLString::release(&p);
237 m_encodedValues.erase(m_encodedValues.begin()+index);
240 SAMLAttribute::removeValue(index);
243 void TargetedID::valueFromDOM(DOMElement* e)
245 // Look for a SAML2 NameID.
246 e=saml::XML::getFirstChildElement(e,::XML::SAML2ASSERT_NS,NameID);
247 if (e && !XMLString::compareString(FORMAT_PERSISTENT,e->getAttributeNS(NULL,L(Format)))) {
248 m_nameQualifiers.push_back(e->getAttributeNS(NULL,L(NameQualifier)));
249 m_spNameQualifiers.push_back(e->getAttributeNS(NULL,SPNameQualifier));
250 if (e->hasChildNodes() && e->getFirstChild()->getNodeType()==DOMNode::TEXT_NODE)
251 m_values.push_back(e->getFirstChild()->getNodeValue());
253 m_values.push_back(&chNull);
257 // Insert a null value placeholder.
258 m_nameQualifiers.push_back(&chNull);
259 m_spNameQualifiers.push_back(&chNull);
260 m_values.push_back(&chNull);
263 void TargetedID::valueToDOM(unsigned int index, DOMElement* e) const
265 const XMLCh* nq=m_nameQualifiers[index];
266 const XMLCh* spnq=m_spNameQualifiers[index];
267 const XMLCh* val=m_values[index];
268 if (!saml::XML::isEmpty(nq) && !saml::XML::isEmpty(spnq) && !saml::XML::isEmpty(val)) {
269 // Build a SAML2 NameID.
270 DOMElement* nameid=e->getOwnerDocument()->createElementNS(::XML::SAML2ASSERT_NS,NameID);
271 nameid->setAttributeNS(NULL,L(Format),FORMAT_PERSISTENT);
272 nameid->setAttributeNS(NULL,L(NameQualifier),nq);
273 nameid->setAttributeNS(NULL,SPNameQualifier,spnq);
274 nameid->appendChild(e->getOwnerDocument()->createTextNode(val));
275 e->appendChild(nameid);
279 SAMLObject* TargetedID::clone() const
281 return new TargetedID(m_name,m_namespace,m_type,m_lifetime,m_values,m_nameQualifiers,m_spNameQualifiers);
284 const XMLCh TargetedID::NameID[] =
285 { chLatin_N, chLatin_a, chLatin_m, chLatin_e, chLatin_I, chLatin_D, chNull };
287 const XMLCh TargetedID::SPNameQualifier[] =
288 { chLatin_S, chLatin_P, chLatin_N, chLatin_a, chLatin_m, chLatin_e,
289 chLatin_Q, chLatin_u, chLatin_a, chLatin_l, chLatin_i, chLatin_f, chLatin_i, chLatin_e, chLatin_r, chNull
292 const XMLCh TargetedID::FORMAT_PERSISTENT[] =
294 chLatin_u, chLatin_r, chLatin_n, chColon, chLatin_o, chLatin_a, chLatin_s, chLatin_i, chLatin_s, chColon,
295 chLatin_n, chLatin_a, chLatin_m, chLatin_e, chLatin_s, chColon, chLatin_t, chLatin_c, chColon,
296 chLatin_S, chLatin_A, chLatin_M, chLatin_L, chColon, chDigit_2, chPeriod, chDigit_0, chColon,
297 chLatin_n, chLatin_a, chLatin_m, chLatin_e, chLatin_i, chLatin_d, chDash,
298 chLatin_f, chLatin_o, chLatin_r, chLatin_m, chLatin_a, chLatin_t, chColon,
299 chLatin_p, chLatin_e, chLatin_r, chLatin_s, chLatin_i, chLatin_s, chLatin_t, chLatin_e, chLatin_n, chLatin_t, chNull