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