Simple and Scoped Attribute decoders.
[shibboleth/cpp-sp.git] / shibsp / attribute / ScopedAttributeDecoder.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  * ScopedAttributeDecoder.cpp\r
19  * \r
20  * Decodes SAML into ScopedAttributes\r
21  */\r
22 \r
23 #include "internal.h"\r
24 #include "attribute/AttributeDecoder.h"\r
25 #include "attribute/ScopedAttribute.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     class ScopedAttributeDecoder : virtual public AttributeDecoder\r
40     {\r
41     public:\r
42         ScopedAttributeDecoder(const DOMElement* e) {}\r
43         ~ScopedAttributeDecoder() {}\r
44 \r
45         shibsp::Attribute* decode(const char* id, const XMLObject* xmlObject) const;\r
46     };\r
47 \r
48     AttributeDecoder* SHIBSP_DLLLOCAL ScopedAttributeDecoderFactory(const DOMElement* const & e)\r
49     {\r
50         return new ScopedAttributeDecoder(e);\r
51     }\r
52 \r
53     static const XMLCh Scope[] = UNICODE_LITERAL_5(S,c,o,p,e);\r
54 };\r
55 \r
56 shibsp::Attribute* ScopedAttributeDecoder::decode(const char* id, const XMLObject* xmlObject) const\r
57 {\r
58     char* val;\r
59     char* scope;\r
60     const XMLCh* xmlscope;\r
61     QName scopeqname(NULL,Scope);\r
62     auto_ptr<ScopedAttribute> scoped(new ScopedAttribute(id));\r
63     vector< pair<string,string> >& dest = scoped->getValues();\r
64     vector<XMLObject*>::const_iterator v,stop;\r
65 \r
66     Category& log = Category::getInstance(SHIBSP_LOGCAT".AttributeDecoder");\r
67     \r
68     if (xmlObject && XMLString::equals(opensaml::saml1::Attribute::LOCAL_NAME,xmlObject->getElementQName().getLocalPart())) {\r
69         const opensaml::saml2::Attribute* saml2attr = dynamic_cast<const opensaml::saml2::Attribute*>(xmlObject);\r
70         if (saml2attr) {\r
71             const vector<XMLObject*>& values = saml2attr->getAttributeValues();\r
72             v = values.begin();\r
73             stop = values.end();\r
74             if (log.isDebugEnabled()) {\r
75                 auto_ptr_char n(saml2attr->getName());\r
76                 log.debug("decoding ScopedAttribute (%s) from SAML 2 Attribute (%s) with %lu value(s)", id, n.get() ? n.get() : "unnamed", values.size());\r
77             }\r
78         }\r
79         else {\r
80             const opensaml::saml1::Attribute* saml1attr = dynamic_cast<const opensaml::saml1::Attribute*>(xmlObject);\r
81             if (saml1attr) {\r
82                 const vector<XMLObject*>& values = saml2attr->getAttributeValues();\r
83                 v = values.begin();\r
84                 stop = values.end();\r
85                 if (log.isDebugEnabled()) {\r
86                     auto_ptr_char n(saml1attr->getAttributeName());\r
87                     log.debug("decoding ScopedAttribute (%s) from SAML 1 Attribute (%s) with %lu value(s)", id, n.get() ? n.get() : "unnamed", values.size());\r
88                 }\r
89             }\r
90             else {\r
91                 log.warn("XMLObject type not recognized by ScopedAttributeDecoder, no values returned");\r
92                 return NULL;\r
93             }\r
94         }\r
95 \r
96         for (; v!=stop; ++v) {\r
97             if (!(*v)->hasChildren()) {\r
98                 val = toUTF8((*v)->getTextContent());\r
99                 if (val && *val) {\r
100                     const AttributeExtensibleXMLObject* aexo=dynamic_cast<const AttributeExtensibleXMLObject*>(*v);\r
101                     xmlscope = aexo->getAttribute(scopeqname);\r
102                     if (xmlscope && *xmlscope) {\r
103                         scope = toUTF8(xmlscope);\r
104                         dest.push_back(make_pair(val,scope));\r
105                         delete[] scope;\r
106                     }\r
107                     else {\r
108                         scope = strchr(val, '@');\r
109                         if (scope) {\r
110                             *scope++ = 0;\r
111                             if (*scope)\r
112                                 dest.push_back(make_pair(val,scope));\r
113                             else\r
114                                 log.warn("ignoring unscoped AttributeValue");\r
115                         }\r
116                         else {\r
117                             log.warn("ignoring unscoped AttributeValue");\r
118                         }\r
119                     }\r
120                 }\r
121                 else {\r
122                     log.warn("skipping empty AttributeValue");\r
123                 }\r
124                 delete[] val;\r
125             }\r
126             else {\r
127                 log.warn("skipping complex AttributeValue");\r
128             }\r
129         }\r
130 \r
131         return dest.empty() ? NULL : scoped.release();\r
132     }\r
133 \r
134     const NameID* saml2name = dynamic_cast<const NameID*>(xmlObject);\r
135     if (saml2name) {\r
136         if (log.isDebugEnabled()) {\r
137             auto_ptr_char f(saml2name->getFormat());\r
138             log.debug("decoding ScopedAttribute (%s) from SAML 2 NameID with Format (%s)", id, f.get() ? f.get() : "unspecified");\r
139         }\r
140         val = toUTF8(saml2name->getName());\r
141     }\r
142     else {\r
143         const NameIdentifier* saml1name = dynamic_cast<const NameIdentifier*>(xmlObject);\r
144         if (saml1name) {\r
145             if (log.isDebugEnabled()) {\r
146                 auto_ptr_char f(saml1name->getFormat());\r
147                 log.debug("decoding ScopedAttribute (%s) from SAML 1 NameIdentifier with Format (%s)", id, f.get() ? f.get() : "unspecified");\r
148             }\r
149             val = toUTF8(saml1name->getName());\r
150         }\r
151         else {\r
152             log.warn("XMLObject type not recognized by ScopedAttributeDecoder, no values returned");\r
153             return NULL;\r
154         }\r
155     }\r
156 \r
157     if (val && *val && *val!='@') {\r
158         scope = strchr(val, '@');\r
159         if (scope) {\r
160             *scope++ = 0;\r
161             if (*scope)\r
162                 dest.push_back(make_pair(val,scope));\r
163             else\r
164                 log.warn("ignoring NameID with no scope");\r
165         }\r
166         else {\r
167             log.warn("ignoring NameID with no scope delimiter (@)");\r
168         }\r
169     }\r
170     else {\r
171         log.warn("ignoring empty NameID");\r
172     }\r
173     delete[] val;\r
174     return dest.empty() ? NULL : scoped.release();\r
175 }\r