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