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