Convert logging to log4shib via compile time switch.
[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 <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 char* id, 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=NULL, const char* relyingParty=NULL\r
52             ) const;\r
53         void extract(\r
54             const NameIdentifier* n, vector<NameIDAttribute::Value>& dest, const char* assertingParty=NULL, const char* relyingParty=NULL\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 char* id, const XMLObject* xmlObject, const char* assertingParty, const char* relyingParty\r
67     ) const\r
68 {\r
69     auto_ptr<NameIDAttribute> nameid(\r
70         new NameIDAttribute(id, (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");\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("decoding NameIDAttribute (%s) from SAML 2 Attribute (%s) with %lu value(s)", id, n.get() ? n.get() : "unnamed", values.size());\r
87             }\r
88         }\r
89         else {\r
90             const opensaml::saml1::Attribute* saml1attr = dynamic_cast<const opensaml::saml1::Attribute*>(xmlObject);\r
91             if (saml1attr) {\r
92                 const vector<XMLObject*>& values = saml1attr->getAttributeValues();\r
93                 v = values.begin();\r
94                 stop = values.end();\r
95                 if (log.isDebugEnabled()) {\r
96                     auto_ptr_char n(saml1attr->getAttributeName());\r
97                     log.debug("decoding NameIDAttribute (%s) from SAML 1 Attribute (%s) with %lu value(s)", id, n.get() ? n.get() : "unnamed", values.size());\r
98                 }\r
99             }\r
100             else {\r
101                 log.warn("XMLObject type not recognized by NameIDAttributeDecoder, no values returned");\r
102                 return NULL;\r
103             }\r
104         }\r
105 \r
106         for (; v!=stop; ++v) {\r
107             const NameIDType* n2 = dynamic_cast<const NameIDType*>(*v);\r
108             if (n2)\r
109                 extract(n2, dest);\r
110             else {\r
111                 const NameIdentifier* n1=dynamic_cast<const NameIdentifier*>(*v);\r
112                 if (n1)\r
113                     extract(n1, dest);\r
114                 else if ((*v)->hasChildren()) {\r
115                     const list<XMLObject*>& values = (*v)->getOrderedChildren();\r
116                     for (list<XMLObject*>::const_iterator vv = values.begin(); vv!=values.end(); ++vv) {\r
117                         if (n2=dynamic_cast<const NameIDType*>(*vv))\r
118                             extract(n2, dest);\r
119                         else if (n1=dynamic_cast<const NameIdentifier*>(*vv))\r
120                             extract(n1, dest);\r
121                         else\r
122                             log.warn("skipping AttributeValue without a recognizable NameID/NameIdentifier");\r
123                     }\r
124                 }\r
125             }\r
126         }\r
127 \r
128         return dest.empty() ? NULL : nameid.release();\r
129     }\r
130 \r
131     const NameIDType* saml2name = dynamic_cast<const NameIDType*>(xmlObject);\r
132     if (saml2name) {\r
133         if (log.isDebugEnabled()) {\r
134             auto_ptr_char f(saml2name->getFormat());\r
135             log.debug("decoding NameIDAttribute (%s) from SAML 2 NameID with Format (%s)", id, f.get() ? f.get() : "unspecified");\r
136         }\r
137         extract(saml2name, dest);\r
138     }\r
139     else {\r
140         const NameIdentifier* saml1name = dynamic_cast<const NameIdentifier*>(xmlObject);\r
141         if (saml1name) {\r
142             if (log.isDebugEnabled()) {\r
143                 auto_ptr_char f(saml1name->getFormat());\r
144                 log.debug("decoding NameIDAttribute (%s) from SAML 1 NameIdentifier with Format (%s)", id, f.get() ? f.get() : "unspecified");\r
145             }\r
146             extract(saml1name, dest);\r
147         }\r
148         else {\r
149             log.warn("XMLObject type not recognized by NameIDAttributeDecoder, no values returned");\r
150             return NULL;\r
151         }\r
152     }\r
153 \r
154     return dest.empty() ? NULL : nameid.release();\r
155 }\r
156 \r
157 void NameIDAttributeDecoder::extract(\r
158     const NameIDType* n, vector<NameIDAttribute::Value>& dest, const char* assertingParty, const char* relyingParty\r
159     ) const\r
160 {\r
161     char* name = toUTF8(n->getName());\r
162     if (name && *name) {\r
163         dest.push_back(NameIDAttribute::Value());\r
164         NameIDAttribute::Value& val = dest.back();\r
165         val.m_Name = name;\r
166         char* str = toUTF8(n->getFormat());\r
167         if (str) {\r
168             val.m_Format = str;\r
169             delete[] str;\r
170         }\r
171         \r
172         str = toUTF8(n->getNameQualifier());\r
173         if (str && *str)\r
174             val.m_NameQualifier = str;\r
175         else if (assertingParty)\r
176             val.m_NameQualifier = assertingParty;\r
177         delete[] str;\r
178         \r
179         str = toUTF8(n->getSPNameQualifier());\r
180         if (str && *str)\r
181             val.m_SPNameQualifier = str;\r
182         else if (relyingParty)\r
183             val.m_SPNameQualifier = relyingParty;\r
184         delete[] str;\r
185         \r
186         str = toUTF8(n->getSPProvidedID());\r
187         if (str) {\r
188             val.m_SPProvidedID = str;\r
189             delete[] str;\r
190         }\r
191     }\r
192     delete[] name;\r
193 }\r
194 \r
195 void NameIDAttributeDecoder::extract(\r
196     const NameIdentifier* n, vector<NameIDAttribute::Value>& dest, const char* assertingParty, const char* relyingParty\r
197     ) const\r
198 {\r
199     char* name = toUTF8(n->getName());\r
200     if (name && *name) {\r
201         dest.push_back(NameIDAttribute::Value());\r
202         NameIDAttribute::Value& val = dest.back();\r
203         val.m_Name = name;\r
204         char* str = toUTF8(n->getFormat());\r
205         if (str) {\r
206             val.m_Format = str;\r
207             delete[] str;\r
208         }\r
209 \r
210         str = toUTF8(n->getNameQualifier());\r
211         if (str && *str)\r
212             val.m_NameQualifier = str;\r
213         else if (assertingParty)\r
214             val.m_NameQualifier = assertingParty;\r
215         delete[] str;\r
216         \r
217         if (relyingParty)\r
218             val.m_SPNameQualifier = relyingParty;\r
219     }\r
220     delete[] name;\r
221 }\r