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