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