551206fa0419c0693befaabd023b2beefabacb95
[shibboleth/cpp-sp.git] / shibsp / attribute / XMLAttributeDecoder.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  * XMLAttributeDecoder.cpp
23  *
24  * Decodes arbitrary XML into an XMLAttribute.
25  */
26
27 #include "internal.h"
28 #include "attribute/AttributeDecoder.h"
29 #include "attribute/XMLAttribute.h"
30
31 #include <saml/saml1/core/Assertions.h>
32 #include <saml/saml2/core/Assertions.h>
33 #include <xmltooling/util/XMLHelper.h>
34
35 using namespace shibsp;
36 using namespace opensaml;
37 using namespace xmltooling;
38 using namespace std;
39
40 namespace shibsp {
41     class SHIBSP_DLLLOCAL XMLAttributeDecoder : virtual public AttributeDecoder
42     {
43     public:
44         XMLAttributeDecoder(const DOMElement* e) : AttributeDecoder(e) {}
45         ~XMLAttributeDecoder() {}
46
47         // deprecated method
48         Attribute* decode(
49             const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty=nullptr, const char* relyingParty=nullptr
50             ) const {
51             return decode(nullptr, ids, xmlObject, assertingParty, relyingParty);
52         }
53
54         Attribute* decode(
55             const GenericRequest*, const vector<string>&, const XMLObject*, const char* assertingParty=nullptr, const char* relyingParty=nullptr
56             ) const;
57
58     private:
59         DDF convert(DOMElement* e, bool nameit=true) const;
60         auto_ptr_char m_formatter;
61         map<pair<xstring,xstring>,string> m_tagMap;
62     };
63
64     AttributeDecoder* SHIBSP_DLLLOCAL XMLAttributeDecoderFactory(const DOMElement* const & e)
65     {
66         return new XMLAttributeDecoder(e);
67     }
68 };
69
70
71 Attribute* XMLAttributeDecoder::decode(
72     const GenericRequest* request, const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty, const char* relyingParty
73     ) const
74 {
75     if (!xmlObject)
76         return nullptr;
77
78     Category& log = Category::getInstance(SHIBSP_LOGCAT".AttributeDecoder.XML");
79
80     auto_ptr<XMLAttribute> attr(new XMLAttribute(ids));
81     vector<string>& dest = attr->getValues();
82
83     // Handle any non-Attribute object directly.
84     if (!xmlObject || !XMLString::equals(saml1::Attribute::LOCAL_NAME, xmlObject->getElementQName().getLocalPart())) {
85         DOMElement* e = xmlObject->getDOM();
86         if (e) {
87             if (log.isDebugEnabled()) {
88                 log.debug(
89                     "decoding XMLAttribute (%s) from XMLObject (%s)",
90                     ids.front().c_str(),
91                     (xmlObject->getSchemaType() ? xmlObject->getSchemaType()->toString() : xmlObject->getElementQName().toString()).c_str()
92                     );
93             }
94             dest.push_back(string());
95             XMLHelper::serialize(e, dest.back());
96         }
97         else {
98             log.warn("skipping XMLObject without a backing DOM");
99         }
100         return dest.empty() ? nullptr : _decode(attr.release());
101     }
102
103     pair<vector<XMLObject*>::const_iterator,vector<XMLObject*>::const_iterator> valrange;
104
105     const saml2::Attribute* saml2attr = dynamic_cast<const saml2::Attribute*>(xmlObject);
106     if (saml2attr) {
107         const vector<XMLObject*>& values = saml2attr->getAttributeValues();
108         valrange = valueRange(request, values);
109         if (log.isDebugEnabled()) {
110             auto_ptr_char n(saml2attr->getName());
111             log.debug(
112                 "decoding XMLAttribute (%s) from SAML 2 Attribute (%s) with %lu value(s)",
113                 ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()
114                 );
115         }
116     }
117     else {
118         const saml1::Attribute* saml1attr = dynamic_cast<const saml1::Attribute*>(xmlObject);
119         if (saml1attr) {
120             const vector<XMLObject*>& values = saml1attr->getAttributeValues();
121             valrange = valueRange(request, values);
122             if (log.isDebugEnabled()) {
123                 auto_ptr_char n(saml1attr->getAttributeName());
124                 log.debug(
125                     "decoding XMLAttribute (%s) from SAML 1 Attribute (%s) with %lu value(s)",
126                     ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()
127                     );
128             }
129         }
130         else {
131             log.warn("XMLObject type not recognized by XMLAttributeDecoder, no values returned");
132             return nullptr;
133         }
134     }
135
136     for (; valrange.first != valrange.second; ++valrange.first) {
137         DOMElement* e = (*valrange.first)->getDOM();
138         if (e) {
139             dest.push_back(string());
140             XMLHelper::serialize(e, dest.back());
141         }
142         else
143             log.warn("skipping AttributeValue without a backing DOM");
144     }
145
146     return dest.empty() ? nullptr : _decode(attr.release());
147 }