Change license header.
[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         Attribute* decode(
48             const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty=nullptr, const char* relyingParty=nullptr
49             ) const;
50
51     private:
52         DDF convert(DOMElement* e, bool nameit=true) const;
53         auto_ptr_char m_formatter;
54         map<pair<xstring,xstring>,string> m_tagMap;
55     };
56
57     AttributeDecoder* SHIBSP_DLLLOCAL XMLAttributeDecoderFactory(const DOMElement* const & e)
58     {
59         return new XMLAttributeDecoder(e);
60     }
61 };
62
63
64 Attribute* XMLAttributeDecoder::decode(
65     const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty, const char* relyingParty
66     ) const
67 {
68     if (!xmlObject)
69         return nullptr;
70
71     Category& log = Category::getInstance(SHIBSP_LOGCAT".AttributeDecoder.XML");
72
73     auto_ptr<XMLAttribute> attr(new XMLAttribute(ids));
74     vector<string>& dest = attr->getValues();
75
76     // Handle any non-Attribute object directly.
77     if (!xmlObject || !XMLString::equals(saml1::Attribute::LOCAL_NAME, xmlObject->getElementQName().getLocalPart())) {
78         DOMElement* e = xmlObject->getDOM();
79         if (e) {
80             if (log.isDebugEnabled()) {
81                 log.debug(
82                     "decoding XMLAttribute (%s) from XMLObject (%s)",
83                     ids.front().c_str(),
84                     (xmlObject->getSchemaType() ? xmlObject->getSchemaType()->toString() : xmlObject->getElementQName().toString()).c_str()
85                     );
86             }
87             dest.push_back(string());
88             XMLHelper::serialize(e, dest.back());
89         }
90         else {
91             log.warn("skipping XMLObject without a backing DOM");
92         }
93         return dest.empty() ? nullptr : _decode(attr.release());
94     }
95
96     vector<XMLObject*>::const_iterator v,stop;
97
98     const saml2::Attribute* saml2attr = dynamic_cast<const saml2::Attribute*>(xmlObject);
99     if (saml2attr) {
100         const vector<XMLObject*>& values = saml2attr->getAttributeValues();
101         v = values.begin();
102         stop = values.end();
103         if (log.isDebugEnabled()) {
104             auto_ptr_char n(saml2attr->getName());
105             log.debug(
106                 "decoding XMLAttribute (%s) from SAML 2 Attribute (%s) with %lu value(s)",
107                 ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()
108                 );
109         }
110     }
111     else {
112         const saml1::Attribute* saml1attr = dynamic_cast<const saml1::Attribute*>(xmlObject);
113         if (saml1attr) {
114             const vector<XMLObject*>& values = saml1attr->getAttributeValues();
115             v = values.begin();
116             stop = values.end();
117             if (log.isDebugEnabled()) {
118                 auto_ptr_char n(saml1attr->getAttributeName());
119                 log.debug(
120                     "decoding XMLAttribute (%s) from SAML 1 Attribute (%s) with %lu value(s)",
121                     ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()
122                     );
123             }
124         }
125         else {
126             log.warn("XMLObject type not recognized by XMLAttributeDecoder, no values returned");
127             return nullptr;
128         }
129     }
130
131     for (; v!=stop; ++v) {
132         DOMElement* e = (*v)->getDOM();
133         if (e) {
134             dest.push_back(string());
135             XMLHelper::serialize(e, dest.back());
136         }
137         else
138             log.warn("skipping AttributeValue without a backing DOM");
139     }
140
141     return dest.empty() ? nullptr : _decode(attr.release());
142 }