6a6658277d540170cc4141feea4a5e27215677af
[shibboleth/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         shibsp::Attribute* decode(
51             const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty=nullptr, const char* relyingParty=nullptr
52             ) const;
53     };
54
55     AttributeDecoder* SHIBSP_DLLLOCAL Base64AttributeDecoderFactory(const DOMElement* const & e)
56     {
57         return new Base64AttributeDecoder(e);
58     }
59 };
60
61 shibsp::Attribute* Base64AttributeDecoder::decode(
62     const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty, const char* relyingParty
63     ) const
64 {
65     auto_ptr<SimpleAttribute> simple(new SimpleAttribute(ids));
66     vector<string>& dest = simple->getValues();
67     vector<XMLObject*>::const_iterator v,stop;
68
69     Category& log = Category::getInstance(SHIBSP_LOGCAT".AttributeDecoder.Base64");
70
71     if (xmlObject && XMLString::equals(opensaml::saml1::Attribute::LOCAL_NAME,xmlObject->getElementQName().getLocalPart())) {
72         const opensaml::saml2::Attribute* saml2attr = dynamic_cast<const opensaml::saml2::Attribute*>(xmlObject);
73         if (saml2attr) {
74             const vector<XMLObject*>& values = saml2attr->getAttributeValues();
75             v = values.begin();
76             stop = values.end();
77             if (log.isDebugEnabled()) {
78                 auto_ptr_char n(saml2attr->getName());
79                 log.debug(
80                     "decoding SimpleAttribute (%s) from SAML 2 Attribute (%s) with %lu base64-encoded value(s)",
81                     ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()
82                     );
83             }
84         }
85         else {
86             const opensaml::saml1::Attribute* saml1attr = dynamic_cast<const opensaml::saml1::Attribute*>(xmlObject);
87             if (saml1attr) {
88                 const vector<XMLObject*>& values = saml1attr->getAttributeValues();
89                 v = values.begin();
90                 stop = values.end();
91                 if (log.isDebugEnabled()) {
92                     auto_ptr_char n(saml1attr->getAttributeName());
93                 log.debug(
94                     "decoding SimpleAttribute (%s) from SAML 1 Attribute (%s) with %lu base64-encoded value(s)",
95                     ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()
96                     );
97                 }
98             }
99             else {
100                 log.warn("XMLObject type not recognized by Base64AttributeDecoder, no values returned");
101                 return nullptr;
102             }
103         }
104
105         for (; v!=stop; ++v) {
106             if (!(*v)->hasChildren()) {
107                 auto_ptr_char val((*v)->getTextContent());
108                 if (val.get() && *val.get()) {
109                     xsecsize_t x;
110                     XMLByte* decoded=Base64::decode(reinterpret_cast<const XMLByte*>(val.get()),&x);
111                     if (decoded) {
112                         dest.push_back(reinterpret_cast<char*>(decoded));
113 #ifdef SHIBSP_XERCESC_HAS_XMLBYTE_RELEASE
114                         XMLString::release(&decoded);
115 #else
116                         XMLString::release((char**)&decoded);
117 #endif
118                     }
119                     else {
120                         log.warn("skipping AttributeValue, unable to base64-decode");
121                     }
122                 }
123                 else
124                     log.warn("skipping empty AttributeValue");
125             }
126             else {
127                 log.warn("skipping complex AttributeValue");
128             }
129         }
130
131         return dest.empty() ? nullptr : _decode(simple.release());
132     }
133
134     const NameID* saml2name = dynamic_cast<const NameID*>(xmlObject);
135     if (saml2name) {
136         if (log.isDebugEnabled()) {
137             auto_ptr_char f(saml2name->getFormat());
138             log.debug("decoding SimpleAttribute (%s) from SAML 2 NameID with Format (%s)", ids.front().c_str(), f.get() ? f.get() : "unspecified");
139         }
140         auto_ptr_char val(saml2name->getName());
141         if (val.get() && *val.get()) {
142             xsecsize_t x;
143             XMLByte* decoded=Base64::decode(reinterpret_cast<const XMLByte*>(val.get()),&x);
144             if (decoded) {
145                 dest.push_back(reinterpret_cast<char*>(decoded));
146 #ifdef SHIBSP_XERCESC_HAS_XMLBYTE_RELEASE
147                 XMLString::release(&decoded);
148 #else
149                 XMLString::release((char**)&decoded);
150 #endif
151             }
152             else {
153                 log.warn("ignoring NameID, unable to base64-decode");
154             }
155         }
156         else
157             log.warn("ignoring empty NameID");
158     }
159     else {
160         const NameIdentifier* saml1name = dynamic_cast<const NameIdentifier*>(xmlObject);
161         if (saml1name) {
162             if (log.isDebugEnabled()) {
163                 auto_ptr_char f(saml1name->getFormat());
164                 log.debug(
165                     "decoding SimpleAttribute (%s) from SAML 1 NameIdentifier with Format (%s)",
166                     ids.front().c_str(), f.get() ? f.get() : "unspecified"
167                     );
168             }
169             auto_ptr_char val(saml1name->getName());
170             if (val.get() && *val.get()) {
171                 xsecsize_t x;
172                 XMLByte* decoded=Base64::decode(reinterpret_cast<const XMLByte*>(val.get()),&x);
173                 if (decoded) {
174                     dest.push_back(reinterpret_cast<char*>(decoded));
175     #ifdef SHIBSP_XERCESC_HAS_XMLBYTE_RELEASE
176                     XMLString::release(&decoded);
177     #else
178                     XMLString::release((char**)&decoded);
179     #endif
180                 }
181                 else {
182                     log.warn("ignoring NameIdentifier, unable to base64-decode");
183                 }
184             }
185             else
186                 log.warn("ignoring empty NameIdentifier");
187         }
188         else {
189             log.warn("XMLObject type not recognized by Base64AttributeDecoder, no values returned");
190             return nullptr;
191         }
192     }
193
194     return dest.empty() ? nullptr : _decode(simple.release());
195 }