VS10 solution files, convert from NULL macro to nullptr.
[shibboleth/sp.git] / shibsp / attribute / NameIDAttributeDecoder.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  * NameIDAttributeDecoder.cpp
19  *
20  * Decodes SAML into NameIDAttributes.
21  */
22
23 #include "internal.h"
24 #include "attribute/AttributeDecoder.h"
25 #include "attribute/NameIDAttribute.h"
26
27 #include <saml/saml1/core/Assertions.h>
28 #include <saml/saml2/core/Assertions.h>
29
30 using namespace shibsp;
31 using namespace opensaml::saml1;
32 using namespace opensaml::saml2;
33 using namespace xmltooling;
34 using namespace std;
35
36 namespace shibsp {
37     static const XMLCh formatter[] = UNICODE_LITERAL_9(f,o,r,m,a,t,t,e,r);
38     static const XMLCh defaultQualifiers[] = UNICODE_LITERAL_17(d,e,f,a,u,l,t,Q,u,a,l,i,f,i,e,r,s);
39
40     class SHIBSP_DLLLOCAL NameIDAttributeDecoder : virtual public AttributeDecoder
41     {
42     public:
43         NameIDAttributeDecoder(const DOMElement* e)
44                 : AttributeDecoder(e), m_formatter(e ? e->getAttributeNS(nullptr, formatter) : nullptr), m_defaultQualifiers(false) {
45             const XMLCh* flag = e ? e->getAttributeNS(nullptr, defaultQualifiers) : nullptr;
46             if (flag && (*flag == chLatin_t || *flag == chDigit_1))
47                 m_defaultQualifiers = true;
48         }
49         ~NameIDAttributeDecoder() {}
50
51         shibsp::Attribute* decode(
52             const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty=nullptr, const char* relyingParty=nullptr
53             ) const;
54
55     private:
56         void extract(
57             const NameIDType* n, vector<NameIDAttribute::Value>& dest, const char* assertingParty, const char* relyingParty
58             ) const;
59         void extract(
60             const NameIdentifier* n, vector<NameIDAttribute::Value>& dest, const char* assertingParty, const char* relyingParty
61             ) const;
62         auto_ptr_char m_formatter;
63         bool m_defaultQualifiers;
64     };
65
66     AttributeDecoder* SHIBSP_DLLLOCAL NameIDAttributeDecoderFactory(const DOMElement* const & e)
67     {
68         return new NameIDAttributeDecoder(e);
69     }
70 };
71
72 shibsp::Attribute* NameIDAttributeDecoder::decode(
73     const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty, const char* relyingParty
74     ) const
75 {
76     auto_ptr<NameIDAttribute> nameid(
77         new NameIDAttribute(ids, (m_formatter.get() && *m_formatter.get()) ? m_formatter.get() : DEFAULT_NAMEID_FORMATTER)
78         );
79     vector<NameIDAttribute::Value>& dest = nameid->getValues();
80     vector<XMLObject*>::const_iterator v,stop;
81
82     Category& log = Category::getInstance(SHIBSP_LOGCAT".AttributeDecoder.NameID");
83
84     if (xmlObject && XMLString::equals(opensaml::saml1::Attribute::LOCAL_NAME,xmlObject->getElementQName().getLocalPart())) {
85         const opensaml::saml2::Attribute* saml2attr = dynamic_cast<const opensaml::saml2::Attribute*>(xmlObject);
86         if (saml2attr) {
87             const vector<XMLObject*>& values = saml2attr->getAttributeValues();
88             v = values.begin();
89             stop = values.end();
90             if (log.isDebugEnabled()) {
91                 auto_ptr_char n(saml2attr->getName());
92                 log.debug(
93                     "decoding NameIDAttribute (%s) from SAML 2 Attribute (%s) with %lu value(s)",
94                     ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()
95                     );
96             }
97         }
98         else {
99             const opensaml::saml1::Attribute* saml1attr = dynamic_cast<const opensaml::saml1::Attribute*>(xmlObject);
100             if (saml1attr) {
101                 const vector<XMLObject*>& values = saml1attr->getAttributeValues();
102                 v = values.begin();
103                 stop = values.end();
104                 if (log.isDebugEnabled()) {
105                     auto_ptr_char n(saml1attr->getAttributeName());
106                     log.debug(
107                         "decoding NameIDAttribute (%s) from SAML 1 Attribute (%s) with %lu value(s)",
108                         ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()
109                         );
110                 }
111             }
112             else {
113                 log.warn("XMLObject type not recognized by NameIDAttributeDecoder, no values returned");
114                 return nullptr;
115             }
116         }
117
118         for (; v!=stop; ++v) {
119             const NameIDType* n2 = dynamic_cast<const NameIDType*>(*v);
120             if (n2)
121                 extract(n2, dest, assertingParty, relyingParty);
122             else {
123                 const NameIdentifier* n1=dynamic_cast<const NameIdentifier*>(*v);
124                 if (n1)
125                     extract(n1, dest, assertingParty, relyingParty);
126                 else if ((*v)->hasChildren()) {
127                     const list<XMLObject*>& values = (*v)->getOrderedChildren();
128                     for (list<XMLObject*>::const_iterator vv = values.begin(); vv!=values.end(); ++vv) {
129                         if (n2=dynamic_cast<const NameIDType*>(*vv))
130                             extract(n2, dest, assertingParty, relyingParty);
131                         else if (n1=dynamic_cast<const NameIdentifier*>(*vv))
132                             extract(n1, dest, assertingParty, relyingParty);
133                         else
134                             log.warn("skipping AttributeValue without a recognizable NameID/NameIdentifier");
135                     }
136                 }
137             }
138         }
139
140         return dest.empty() ? nullptr : _decode(nameid.release());
141     }
142
143     const NameIDType* saml2name = dynamic_cast<const NameIDType*>(xmlObject);
144     if (saml2name) {
145         if (log.isDebugEnabled()) {
146             auto_ptr_char f(saml2name->getFormat());
147             log.debug("decoding NameIDAttribute (%s) from SAML 2 NameID with Format (%s)", ids.front().c_str(), f.get() ? f.get() : "unspecified");
148         }
149         extract(saml2name, dest, assertingParty, relyingParty);
150     }
151     else {
152         const NameIdentifier* saml1name = dynamic_cast<const NameIdentifier*>(xmlObject);
153         if (saml1name) {
154             if (log.isDebugEnabled()) {
155                 auto_ptr_char f(saml1name->getFormat());
156                 log.debug(
157                     "decoding NameIDAttribute (%s) from SAML 1 NameIdentifier with Format (%s)",
158                     ids.front().c_str(), f.get() ? f.get() : "unspecified"
159                     );
160             }
161             extract(saml1name, dest, assertingParty, relyingParty);
162         }
163         else {
164             log.warn("XMLObject type not recognized by NameIDAttributeDecoder, no values returned");
165             return nullptr;
166         }
167     }
168
169     return dest.empty() ? nullptr : _decode(nameid.release());
170 }
171
172 void NameIDAttributeDecoder::extract(
173     const NameIDType* n, vector<NameIDAttribute::Value>& dest, const char* assertingParty, const char* relyingParty
174     ) const
175 {
176     auto_arrayptr<char> name(toUTF8(n->getName()));
177     if (name.get() && *name.get()) {
178         dest.push_back(NameIDAttribute::Value());
179         NameIDAttribute::Value& val = dest.back();
180         val.m_Name = name.get();
181         char* str = toUTF8(n->getFormat());
182         if (str) {
183             val.m_Format = str;
184             delete[] str;
185         }
186
187         str = toUTF8(n->getNameQualifier());
188         if (str && *str)
189             val.m_NameQualifier = str;
190         else if (m_defaultQualifiers && assertingParty)
191             val.m_NameQualifier = assertingParty;
192         delete[] str;
193
194         str = toUTF8(n->getSPNameQualifier());
195         if (str && *str)
196             val.m_SPNameQualifier = str;
197         else if (m_defaultQualifiers && relyingParty)
198             val.m_SPNameQualifier = relyingParty;
199         delete[] str;
200
201         str = toUTF8(n->getSPProvidedID());
202         if (str) {
203             val.m_SPProvidedID = str;
204             delete[] str;
205         }
206     }
207 }
208
209 void NameIDAttributeDecoder::extract(
210     const NameIdentifier* n, vector<NameIDAttribute::Value>& dest, const char* assertingParty, const char* relyingParty
211     ) const
212 {
213     auto_arrayptr<char> name(toUTF8(n->getName()));
214     if (name.get() && *name.get()) {
215         dest.push_back(NameIDAttribute::Value());
216         NameIDAttribute::Value& val = dest.back();
217         val.m_Name = name.get();
218         char* str = toUTF8(n->getFormat());
219         if (str) {
220             val.m_Format = str;
221             delete[] str;
222         }
223
224         str = toUTF8(n->getNameQualifier());
225         if (str && *str)
226             val.m_NameQualifier = str;
227         else if (m_defaultQualifiers && assertingParty)
228             val.m_NameQualifier = assertingParty;
229         delete[] str;
230
231         if (m_defaultQualifiers && relyingParty)
232             val.m_SPNameQualifier = relyingParty;
233     }
234 }