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