Tagging 2.4RC1 release.
[shibboleth/sp.git] / shibsp / attribute / Base64AttributeDecoder.cpp
1 /*
2  *  Copyright 2010 The Danish CLARIN Consortium
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /**
18  * Base64AttributeDecoder.cpp
19  *
20  * Decodes SAML containing base64-encoded values into SimpleAttributes.
21  */
22
23 #include "internal.h"
24 #include "attribute/AttributeDecoder.h"
25 #include "attribute/SimpleAttribute.h"
26
27 #include <saml/saml1/core/Assertions.h>
28 #include <saml/saml2/core/Assertions.h>
29
30 #include <xercesc/util/Base64.hpp>
31
32 using namespace shibsp;
33 using namespace opensaml::saml1;
34 using namespace opensaml::saml2;
35 using namespace xmltooling::logging;
36 using namespace xmltooling;
37 using namespace std;
38
39 namespace shibsp {
40     class SHIBSP_DLLLOCAL Base64AttributeDecoder : virtual public AttributeDecoder
41     {
42     public:
43         Base64AttributeDecoder(const DOMElement* e) : AttributeDecoder(e) {}
44         ~Base64AttributeDecoder() {}
45
46         shibsp::Attribute* decode(
47             const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty=nullptr, const char* relyingParty=nullptr
48             ) const;
49     };
50
51     AttributeDecoder* SHIBSP_DLLLOCAL Base64AttributeDecoderFactory(const DOMElement* const & e)
52     {
53         return new Base64AttributeDecoder(e);
54     }
55 };
56
57 shibsp::Attribute* Base64AttributeDecoder::decode(
58     const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty, const char* relyingParty
59     ) const
60 {
61     auto_ptr<SimpleAttribute> simple(new SimpleAttribute(ids));
62     vector<string>& dest = simple->getValues();
63     vector<XMLObject*>::const_iterator v,stop;
64
65     Category& log = Category::getInstance(SHIBSP_LOGCAT".AttributeDecoder.Base64");
66
67     if (xmlObject && XMLString::equals(opensaml::saml1::Attribute::LOCAL_NAME,xmlObject->getElementQName().getLocalPart())) {
68         const opensaml::saml2::Attribute* saml2attr = dynamic_cast<const opensaml::saml2::Attribute*>(xmlObject);
69         if (saml2attr) {
70             const vector<XMLObject*>& values = saml2attr->getAttributeValues();
71             v = values.begin();
72             stop = values.end();
73             if (log.isDebugEnabled()) {
74                 auto_ptr_char n(saml2attr->getName());
75                 log.debug(
76                     "decoding SimpleAttribute (%s) from SAML 2 Attribute (%s) with %lu base64-encoded value(s)",
77                     ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()
78                     );
79             }
80         }
81         else {
82             const opensaml::saml1::Attribute* saml1attr = dynamic_cast<const opensaml::saml1::Attribute*>(xmlObject);
83             if (saml1attr) {
84                 const vector<XMLObject*>& values = saml1attr->getAttributeValues();
85                 v = values.begin();
86                 stop = values.end();
87                 if (log.isDebugEnabled()) {
88                     auto_ptr_char n(saml1attr->getAttributeName());
89                 log.debug(
90                     "decoding SimpleAttribute (%s) from SAML 1 Attribute (%s) with %lu base64-encoded value(s)",
91                     ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()
92                     );
93                 }
94             }
95             else {
96                 log.warn("XMLObject type not recognized by Base64AttributeDecoder, no values returned");
97                 return nullptr;
98             }
99         }
100
101         for (; v!=stop; ++v) {
102             if (!(*v)->hasChildren()) {
103                 auto_ptr_char val((*v)->getTextContent());
104                 if (val.get() && *val.get()) {
105                     xsecsize_t x;
106                     XMLByte* decoded=Base64::decode(reinterpret_cast<const XMLByte*>(val.get()),&x);
107                     if (decoded) {
108                         dest.push_back(reinterpret_cast<char*>(decoded));
109 #ifdef SHIBSP_XERCESC_HAS_XMLBYTE_RELEASE
110                         XMLString::release(&decoded);
111 #else
112                         XMLString::release((char**)&decoded);
113 #endif
114                     }
115                     else {
116                         log.warn("skipping AttributeValue, unable to base64-decode");
117                     }
118                 }
119                 else
120                     log.warn("skipping empty AttributeValue");
121             }
122             else {
123                 log.warn("skipping complex AttributeValue");
124             }
125         }
126
127         return dest.empty() ? nullptr : _decode(simple.release());
128     }
129
130     const NameID* saml2name = dynamic_cast<const NameID*>(xmlObject);
131     if (saml2name) {
132         if (log.isDebugEnabled()) {
133             auto_ptr_char f(saml2name->getFormat());
134             log.debug("decoding SimpleAttribute (%s) from SAML 2 NameID with Format (%s)", ids.front().c_str(), f.get() ? f.get() : "unspecified");
135         }
136         auto_ptr_char val(saml2name->getName());
137         if (val.get() && *val.get()) {
138             xsecsize_t x;
139             XMLByte* decoded=Base64::decode(reinterpret_cast<const XMLByte*>(val.get()),&x);
140             if (decoded) {
141                 dest.push_back(reinterpret_cast<char*>(decoded));
142 #ifdef SHIBSP_XERCESC_HAS_XMLBYTE_RELEASE
143                 XMLString::release(&decoded);
144 #else
145                 XMLString::release((char**)&decoded);
146 #endif
147             }
148             else {
149                 log.warn("ignoring NameID, unable to base64-decode");
150             }
151         }
152         else
153             log.warn("ignoring empty NameID");
154     }
155     else {
156         const NameIdentifier* saml1name = dynamic_cast<const NameIdentifier*>(xmlObject);
157         if (saml1name) {
158             if (log.isDebugEnabled()) {
159                 auto_ptr_char f(saml1name->getFormat());
160                 log.debug(
161                     "decoding SimpleAttribute (%s) from SAML 1 NameIdentifier with Format (%s)",
162                     ids.front().c_str(), f.get() ? f.get() : "unspecified"
163                     );
164             }
165             auto_ptr_char val(saml1name->getName());
166             if (val.get() && *val.get()) {
167                 xsecsize_t x;
168                 XMLByte* decoded=Base64::decode(reinterpret_cast<const XMLByte*>(val.get()),&x);
169                 if (decoded) {
170                     dest.push_back(reinterpret_cast<char*>(decoded));
171     #ifdef SHIBSP_XERCESC_HAS_XMLBYTE_RELEASE
172                     XMLString::release(&decoded);
173     #else
174                     XMLString::release((char**)&decoded);
175     #endif
176                 }
177                 else {
178                     log.warn("ignoring NameIdentifier, unable to base64-decode");
179                 }
180             }
181             else
182                 log.warn("ignoring empty NameIdentifier");
183         }
184         else {
185             log.warn("XMLObject type not recognized by Base64AttributeDecoder, no values returned");
186             return nullptr;
187         }
188     }
189
190     return dest.empty() ? nullptr : _decode(simple.release());
191 }