2 * Copyright 2001-2005 Internet2
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 /* TargetedID.cpp - eduPersonTargetedID custom attribute handling
26 #include <xercesc/util/Base64.hpp>
28 using namespace shibboleth;
33 class TargetedID : public SAMLAttribute
37 const XMLCh* name=NULL,
39 const saml::QName* type=NULL,
41 const Iterator<const XMLCh*>& values=EMPTY(const XMLCh*),
42 const Iterator<const XMLCh*>& nameQualifiers=EMPTY(const XMLCh*),
43 const Iterator<const XMLCh*>& spNameQualifiers=EMPTY(const XMLCh*)
45 TargetedID(DOMElement* e);
46 TargetedID(istream& in);
49 saml::SAMLObject* clone() const;
51 saml::Iterator<const XMLCh*> getValues() const;
52 saml::Iterator<std::string> getSingleByteValues() const;
54 void setValues(const saml::Iterator<const XMLCh*>& values=EMPTY(const XMLCh*)) {
55 throw SAMLException("unsupported operation");
57 void addValue(const XMLCh* value) {
58 throw SAMLException("unsupported operation");
60 void removeValue(unsigned long index);
62 static const XMLCh NameID[];
63 static const XMLCh SPNameQualifier[];
64 static const XMLCh FORMAT_PERSISTENT[];
66 void valueToDOM(unsigned int index, DOMElement* e) const;
67 void valueFromDOM(DOMElement* e);
71 vector<const XMLCh*> m_nameQualifiers;
72 vector<const XMLCh*> m_spNameQualifiers;
73 mutable vector<const XMLCh*> m_encodedValues;
76 struct TargetedIDBuilder : public virtual IAttributeFactory
78 TargetedIDBuilder(const DOMElement* e) {}
79 SAMLAttribute* build(DOMElement* e) const {
80 return new TargetedID(e);
85 IPlugIn* TargetedIDFactory(const DOMElement* e)
87 return new TargetedIDBuilder(e);
90 TargetedID::TargetedID(
93 const saml::QName* type,
95 const Iterator<const XMLCh*>& values,
96 const Iterator<const XMLCh*>& nameQualifiers,
97 const Iterator<const XMLCh*>& spNameQualifiers
98 ) : SAMLAttribute(name,ns,NULL,lifetime,values)
101 if (values.size()!=nameQualifiers.size() || values.size()!=spNameQualifiers.size())
102 throw MalformedException("TargetedID() requires the number of qualifiers to equal the number of values");
104 while (nameQualifiers.hasNext())
105 m_nameQualifiers.push_back(saml::XML::assign(nameQualifiers.next()));
106 while (spNameQualifiers.hasNext())
107 m_spNameQualifiers.push_back(saml::XML::assign(spNameQualifiers.next()));
110 TargetedID::TargetedID(DOMElement* e) : SAMLAttribute(e,false)
116 TargetedID::TargetedID(istream& in) : SAMLAttribute(in,false)
119 fromDOM(m_document->getDocumentElement());
122 TargetedID::~TargetedID()
125 for (vector<const XMLCh*>::iterator i=m_nameQualifiers.begin(); i!=m_nameQualifiers.end(); i++) {
126 XMLCh* p = const_cast<XMLCh*>(*i);
127 XMLString::release(&p);
129 for (vector<const XMLCh*>::iterator j=m_spNameQualifiers.begin(); j!=m_spNameQualifiers.end(); j++) {
130 XMLCh* p = const_cast<XMLCh*>(*j);
131 XMLString::release(&p);
135 // We always own any encoded values we've built.
136 for (vector<const XMLCh*>::iterator i=m_encodedValues.begin(); i!=m_encodedValues.end(); i++) {
137 XMLCh* p = const_cast<XMLCh*>(*i);
138 XMLString::release(&p);
142 void TargetedID::ownStrings()
144 if (!m_bOwnStrings) {
145 for (vector<const XMLCh*>::iterator i=m_nameQualifiers.begin(); i!=m_nameQualifiers.end(); i++)
146 (*i)=saml::XML::assign(*i);
147 for (vector<const XMLCh*>::iterator j=m_spNameQualifiers.begin(); j!=m_spNameQualifiers.end(); j++)
148 (*j)=saml::XML::assign(*j);
149 SAMLAttribute::ownStrings();
153 Iterator<const XMLCh*> TargetedID::getValues() const
155 if (m_encodedValues.empty()) {
156 getSingleByteValues();
157 for (vector<string>::const_iterator i=m_sbValues.begin(); i!=m_sbValues.end(); i++)
158 m_encodedValues.push_back(XMLString::transcode(i->c_str()));
160 return m_encodedValues;
163 Iterator<string> TargetedID::getSingleByteValues() const
165 if (m_sbValues.empty()) {
166 for (unsigned long i=0; i<m_values.size(); i++) {
167 auto_ptr_char a(m_nameQualifiers[i]);
168 auto_ptr_char b(m_spNameQualifiers[i]);
169 auto_ptr_char c(m_values[i]);
170 if (a.get() && *(a.get()) && b.get() && *(b.get()) && c.get() && *(c.get())) {
171 string cat(a.get()); cat+="!"; cat+=b.get(); cat+="!"; cat+=c.get();
172 m_sbValues.push_back(cat);
175 m_sbValues.push_back("");
181 void TargetedID::removeValue(unsigned long index)
184 XMLCh* p=const_cast<XMLCh*>(m_nameQualifiers[index]);
185 XMLString::release(&p);
186 p=const_cast<XMLCh*>(m_spNameQualifiers[index]);
187 XMLString::release(&p);
189 m_nameQualifiers.erase(m_nameQualifiers.begin()+index);
190 m_spNameQualifiers.erase(m_spNameQualifiers.begin()+index);
192 if (!m_encodedValues.empty()) {
193 XMLCh* p=const_cast<XMLCh*>(m_encodedValues[index]);
194 XMLString::release(&p);
195 m_encodedValues.erase(m_encodedValues.begin()+index);
198 SAMLAttribute::removeValue(index);
201 void TargetedID::valueFromDOM(DOMElement* e)
203 // Look for a SAML2 NameID.
204 e=saml::XML::getFirstChildElement(e,::XML::SAML2ASSERT_NS,NameID);
205 if (e && !XMLString::compareString(FORMAT_PERSISTENT,e->getAttributeNS(NULL,L(Format)))) {
206 m_nameQualifiers.push_back(e->getAttributeNS(NULL,L(NameQualifier)));
207 m_spNameQualifiers.push_back(e->getAttributeNS(NULL,SPNameQualifier));
208 if (e->hasChildNodes() && e->getFirstChild()->getNodeType()==DOMNode::TEXT_NODE)
209 m_values.push_back(e->getFirstChild()->getNodeValue());
211 m_values.push_back(&chNull);
215 // Insert a null value placeholder.
216 m_nameQualifiers.push_back(&chNull);
217 m_spNameQualifiers.push_back(&chNull);
218 m_values.push_back(&chNull);
221 void TargetedID::valueToDOM(unsigned int index, DOMElement* e) const
223 const XMLCh* nq=m_nameQualifiers[index];
224 const XMLCh* spnq=m_spNameQualifiers[index];
225 const XMLCh* val=m_values[index];
226 if (!saml::XML::isEmpty(nq) && !saml::XML::isEmpty(spnq) && !saml::XML::isEmpty(val)) {
227 // Build a SAML2 NameID.
228 DOMElement* nameid=e->getOwnerDocument()->createElementNS(::XML::SAML2ASSERT_NS,NameID);
229 nameid->setAttributeNS(NULL,L(Format),FORMAT_PERSISTENT);
230 nameid->setAttributeNS(NULL,L(NameQualifier),nq);
231 nameid->setAttributeNS(NULL,SPNameQualifier,spnq);
232 nameid->appendChild(e->getOwnerDocument()->createTextNode(val));
233 e->appendChild(nameid);
237 SAMLObject* TargetedID::clone() const
239 return new TargetedID(m_name,m_namespace,m_type,m_lifetime,m_values,m_nameQualifiers,m_spNameQualifiers);
242 const XMLCh TargetedID::NameID[] =
243 { chLatin_N, chLatin_a, chLatin_m, chLatin_e, chLatin_I, chLatin_D, chNull };
245 const XMLCh TargetedID::SPNameQualifier[] =
246 { chLatin_S, chLatin_P, chLatin_N, chLatin_a, chLatin_m, chLatin_e,
247 chLatin_Q, chLatin_u, chLatin_a, chLatin_l, chLatin_i, chLatin_f, chLatin_i, chLatin_e, chLatin_r, chNull
250 const XMLCh TargetedID::FORMAT_PERSISTENT[] =
252 chLatin_u, chLatin_r, chLatin_n, chColon, chLatin_o, chLatin_a, chLatin_s, chLatin_i, chLatin_s, chColon,
253 chLatin_n, chLatin_a, chLatin_m, chLatin_e, chLatin_s, chColon, chLatin_t, chLatin_c, chColon,
254 chLatin_S, chLatin_A, chLatin_M, chLatin_L, chColon, chDigit_2, chPeriod, chDigit_0, chColon,
255 chLatin_n, chLatin_a, chLatin_m, chLatin_e, chLatin_i, chLatin_d, chDash,
256 chLatin_f, chLatin_o, chLatin_r, chLatin_m, chLatin_a, chLatin_t, chColon,
257 chLatin_p, chLatin_e, chLatin_r, chLatin_s, chLatin_i, chLatin_s, chLatin_t, chLatin_e, chLatin_n, chLatin_t, chNull