-/*\r
- * Copyright 2009 Internet2\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-/**\r
- * DOMAttributeDecoder.cpp\r
- *\r
- * Decodes a DOM into an ExtensibleAttribute.\r
- */\r
-\r
-#include "internal.h"\r
-#include "attribute/AttributeDecoder.h"\r
-#include "attribute/ExtensibleAttribute.h"\r
-\r
-#include <saml/saml1/core/Assertions.h>\r
-#include <saml/saml2/core/Assertions.h>\r
-#include <xmltooling/util/XMLHelper.h>\r
-\r
-using namespace shibsp;\r
-using namespace opensaml;\r
-using namespace xmltooling;\r
-using namespace std;\r
-\r
-namespace shibsp {\r
- class SHIBSP_DLLLOCAL DOMAttributeDecoder : virtual public AttributeDecoder\r
- {\r
- public:\r
- DOMAttributeDecoder(const DOMElement* e);\r
- ~DOMAttributeDecoder() {}\r
-\r
- Attribute* decode(\r
- const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty=NULL, const char* relyingParty=NULL\r
- ) const;\r
-\r
- private:\r
- DDF convert(DOMElement* e, bool nameit=true) const;\r
- auto_ptr_char m_formatter;\r
- map<pair<xstring,xstring>,string> m_tagMap;\r
- };\r
-\r
- AttributeDecoder* SHIBSP_DLLLOCAL DOMAttributeDecoderFactory(const DOMElement* const & e)\r
- {\r
- return new DOMAttributeDecoder(e);\r
- }\r
-\r
- static const XMLCh Mapping[] = UNICODE_LITERAL_7(M,a,p,p,i,n,g);\r
- static const XMLCh _from[] = UNICODE_LITERAL_4(f,r,o,m);\r
- static const XMLCh _to[] = UNICODE_LITERAL_2(t,o);\r
- static const XMLCh formatter[] = UNICODE_LITERAL_9(f,o,r,m,a,t,t,e,r);\r
-};\r
-\r
-DOMAttributeDecoder::DOMAttributeDecoder(const DOMElement* e)\r
- : AttributeDecoder(e), m_formatter(e ? e->getAttributeNS(NULL,formatter) : NULL)\r
-{\r
- Category& log = Category::getInstance(SHIBSP_LOGCAT".AttributeDecoder.DOM");\r
-\r
- e = e ? XMLHelper::getFirstChildElement(e, Mapping) : NULL;\r
- while (e) {\r
- if (e->hasAttributeNS(NULL, _from) && e->hasAttributeNS(NULL, _to)) {\r
- auto_ptr<xmltooling::QName> f(XMLHelper::getNodeValueAsQName(e->getAttributeNodeNS(NULL, _from)));\r
- auto_ptr_char t(e->getAttributeNS(NULL, _to));\r
- if (f.get() && t.get() && *t.get()) {\r
- if (log.isDebugEnabled())\r
- log.debug("mapping (%s) to (%s)", f->toString().c_str(), t.get());\r
- m_tagMap.insert(\r
- pair< const pair<xstring,xstring>,string>(\r
- pair<xstring,xstring>(f->getLocalPart(), f->hasNamespaceURI() ? f->getNamespaceURI() : &chNull),\r
- t.get()\r
- )\r
- );\r
- }\r
- }\r
- e = XMLHelper::getNextSiblingElement(e, Mapping);\r
- }\r
-}\r
-\r
-Attribute* DOMAttributeDecoder::decode(\r
- const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty, const char* relyingParty\r
- ) const\r
-{\r
- Category& log = Category::getInstance(SHIBSP_LOGCAT".AttributeDecoder.DOM");\r
-\r
- if (!xmlObject || !XMLString::equals(saml1::Attribute::LOCAL_NAME, xmlObject->getElementQName().getLocalPart())) {\r
- log.warn("XMLObject type not recognized by DOMAttributeDecoder, no values returned");\r
- return NULL;\r
- }\r
-\r
- auto_ptr<ExtensibleAttribute> attr(new ExtensibleAttribute(ids, m_formatter.get()));\r
- DDF dest = attr->getValues();\r
- vector<XMLObject*>::const_iterator v,stop;\r
-\r
- const saml2::Attribute* saml2attr = dynamic_cast<const saml2::Attribute*>(xmlObject);\r
- if (saml2attr) {\r
- const vector<XMLObject*>& values = saml2attr->getAttributeValues();\r
- v = values.begin();\r
- stop = values.end();\r
- if (log.isDebugEnabled()) {\r
- auto_ptr_char n(saml2attr->getName());\r
- log.debug(\r
- "decoding ExtensibleAttribute (%s) from SAML 2 Attribute (%s) with %lu value(s)",\r
- ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()\r
- );\r
- }\r
- }\r
- else {\r
- const saml1::Attribute* saml1attr = dynamic_cast<const saml1::Attribute*>(xmlObject);\r
- if (saml1attr) {\r
- const vector<XMLObject*>& values = saml1attr->getAttributeValues();\r
- v = values.begin();\r
- stop = values.end();\r
- if (log.isDebugEnabled()) {\r
- auto_ptr_char n(saml1attr->getAttributeName());\r
- log.debug(\r
- "decoding ExtensibleAttribute (%s) from SAML 1 Attribute (%s) with %lu value(s)",\r
- ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()\r
- );\r
- }\r
- }\r
- else {\r
- log.warn("XMLObject type not recognized by DOMAttributeDecoder, no values returned");\r
- return NULL;\r
- }\r
- }\r
-\r
- for (; v!=stop; ++v) {\r
- DOMElement* e = (*v)->getDOM();\r
- if (e) {\r
- DDF converted = convert(e, false);\r
- if (!converted.isnull())\r
- dest.add(converted);\r
- }\r
- else\r
- log.warn("skipping AttributeValue without a backing DOM");\r
- }\r
-\r
- return dest.integer() ? _decode(attr.release()) : NULL;\r
-}\r
-\r
-DDF DOMAttributeDecoder::convert(DOMElement* e, bool nameit) const\r
-{\r
- const XMLCh* nsURI;\r
- const XMLCh* local;\r
- map<pair<xstring,xstring>,string>::const_iterator mapping;\r
- DDF obj = DDF(NULL).structure();\r
-\r
- if (nameit) {\r
- // Name this structure.\r
- nsURI = e->getNamespaceURI();\r
- local = e->getLocalName();\r
- mapping = m_tagMap.find(pair<xstring,xstring>(local,nsURI));\r
- if (mapping == m_tagMap.end()) {\r
- auto_ptr_char temp(local);\r
- obj.name(temp.get());\r
- }\r
- else {\r
- obj.name(mapping->second.c_str());\r
- }\r
- }\r
-\r
- // Process non-xmlns attributes.\r
- DOMNamedNodeMap* attrs = e->getAttributes();\r
- for (XMLSize_t a = attrs->getLength(); a > 0; --a) {\r
- DOMNode* attr = attrs->item(a-1);\r
- nsURI = attr->getNamespaceURI();\r
- if (XMLString::equals(nsURI, xmlconstants::XMLNS_NS))\r
- continue;\r
- local = attr->getLocalName();\r
- mapping = m_tagMap.find(pair<xstring,xstring>(local, nsURI ? nsURI : &chNull));\r
- if (mapping == m_tagMap.end()) {\r
- auto_ptr_char temp(local);\r
- obj.addmember(temp.get()).string(toUTF8(attr->getNodeValue(), true), false);\r
- }\r
- else {\r
- obj.addmember(mapping->second.c_str()).string(toUTF8(attr->getNodeValue(), true), false);\r
- }\r
- }\r
-\r
- DOMElement* child = XMLHelper::getFirstChildElement(e);\r
- if (!child && e->hasChildNodes() && e->getFirstChild()->getNodeType() == DOMNode::TEXT_NODE) {\r
- // Attach a _text member if a text node is present.\r
- obj.addmember("_string").string(toUTF8(e->getFirstChild()->getNodeValue(), true), false);\r
- }\r
- else {\r
- while (child) {\r
- // Convert the child element.\r
- DDF converted = convert(child);\r
- if (!converted.isnull()) {\r
- // Now identify it and attach it.\r
- if (obj[converted.name()].isnull()) {\r
- // We're a new child, so just attach as a structure member.\r
- obj.add(converted);\r
- }\r
- else if (obj[converted.name()].islist()) {\r
- // We're already a repeating child, so add it to the list.\r
- obj[converted.name()].add(converted);\r
- }\r
- else if (obj[converted.name()].isstruct()) {\r
- // This is the complex case where we see a child for the second\r
- // time and have to convert a structure member into a named list.\r
- DDF newlist = DDF(converted.name()).list();\r
- newlist.add(obj[converted.name()].remove());\r
- newlist.add(converted);\r
- obj.add(newlist);\r
- }\r
- }\r
- child = XMLHelper::getNextSiblingElement(child);\r
- }\r
- }\r
-\r
- // If we're empty, just delete.\r
- if (obj.integer() == 0)\r
- obj.destroy();\r
- return obj;\r
-}\r
+/**
+ * Licensed to the University Corporation for Advanced Internet
+ * Development, Inc. (UCAID) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * UCAID licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ */
+
+/**
+ * DOMAttributeDecoder.cpp
+ *
+ * Decodes a DOM into an ExtensibleAttribute.
+ */
+
+#include "internal.h"
+#include "attribute/AttributeDecoder.h"
+#include "attribute/ExtensibleAttribute.h"
+
+#include <saml/saml1/core/Assertions.h>
+#include <saml/saml2/core/Assertions.h>
+#include <xmltooling/util/XMLHelper.h>
+
+using namespace shibsp;
+using namespace opensaml;
+using namespace xmltooling;
+using namespace std;
+
+namespace shibsp {
+ class SHIBSP_DLLLOCAL DOMAttributeDecoder : virtual public AttributeDecoder
+ {
+ public:
+ DOMAttributeDecoder(const DOMElement* e);
+ ~DOMAttributeDecoder() {}
+
+ Attribute* decode(
+ const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty=nullptr, const char* relyingParty=nullptr
+ ) const;
+
+ private:
+ DDF convert(DOMElement* e, bool nameit=true) const;
+ string m_formatter;
+ map<pair<xstring,xstring>,string> m_tagMap;
+ };
+
+ AttributeDecoder* SHIBSP_DLLLOCAL DOMAttributeDecoderFactory(const DOMElement* const & e)
+ {
+ return new DOMAttributeDecoder(e);
+ }
+
+ static const XMLCh Mapping[] = UNICODE_LITERAL_7(M,a,p,p,i,n,g);
+ static const XMLCh _from[] = UNICODE_LITERAL_4(f,r,o,m);
+ static const XMLCh _to[] = UNICODE_LITERAL_2(t,o);
+ static const XMLCh formatter[] =UNICODE_LITERAL_9(f,o,r,m,a,t,t,e,r);
+};
+
+DOMAttributeDecoder::DOMAttributeDecoder(const DOMElement* e)
+ : AttributeDecoder(e), m_formatter(XMLHelper::getAttrString(e, nullptr, formatter))
+{
+ Category& log = Category::getInstance(SHIBSP_LOGCAT".AttributeDecoder.DOM");
+
+ e = XMLHelper::getFirstChildElement(e, Mapping);
+ while (e) {
+ if (e->hasAttributeNS(nullptr, _from) && e->hasAttributeNS(nullptr, _to)) {
+ auto_ptr<xmltooling::QName> f(XMLHelper::getNodeValueAsQName(e->getAttributeNodeNS(nullptr, _from)));
+ auto_ptr_char t(e->getAttributeNS(nullptr, _to));
+ if (f.get() && t.get() && *t.get()) {
+ if (log.isDebugEnabled())
+ log.debug("mapping (%s) to (%s)", f->toString().c_str(), t.get());
+ m_tagMap.insert(
+ pair< const pair<xstring,xstring>,string>(
+ pair<xstring,xstring>(f->getLocalPart(), f->hasNamespaceURI() ? f->getNamespaceURI() : &chNull),
+ t.get()
+ )
+ );
+ }
+ }
+ e = XMLHelper::getNextSiblingElement(e, Mapping);
+ }
+}
+
+Attribute* DOMAttributeDecoder::decode(
+ const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty, const char* relyingParty
+ ) const
+{
+ Category& log = Category::getInstance(SHIBSP_LOGCAT".AttributeDecoder.DOM");
+
+ if (!xmlObject)
+ return nullptr;
+
+ auto_ptr<ExtensibleAttribute> attr(new ExtensibleAttribute(ids, m_formatter.c_str()));
+ DDF dest = attr->getValues();
+ vector<XMLObject*> genericObjectWrapper; // used to support stand-alone object decoding
+ vector<XMLObject*>::const_iterator v,stop;
+
+ const saml2::Attribute* saml2attr = dynamic_cast<const saml2::Attribute*>(xmlObject);
+ if (saml2attr) {
+ const vector<XMLObject*>& values = saml2attr->getAttributeValues();
+ v = values.begin();
+ stop = values.end();
+ if (log.isDebugEnabled()) {
+ auto_ptr_char n(saml2attr->getName());
+ log.debug(
+ "decoding ExtensibleAttribute (%s) from SAML 2 Attribute (%s) with %lu value(s)",
+ ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()
+ );
+ }
+ }
+ else {
+ const saml1::Attribute* saml1attr = dynamic_cast<const saml1::Attribute*>(xmlObject);
+ if (saml1attr) {
+ const vector<XMLObject*>& values = saml1attr->getAttributeValues();
+ v = values.begin();
+ stop = values.end();
+ if (log.isDebugEnabled()) {
+ auto_ptr_char n(saml1attr->getAttributeName());
+ log.debug(
+ "decoding ExtensibleAttribute (%s) from SAML 1 Attribute (%s) with %lu value(s)",
+ ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()
+ );
+ }
+ }
+ else {
+ log.debug("decoding arbitrary XMLObject type (%s)", xmlObject->getElementQName().toString().c_str());
+ genericObjectWrapper.push_back(const_cast<XMLObject*>(xmlObject));
+ v = genericObjectWrapper.begin();
+ stop = genericObjectWrapper.end();
+ }
+ }
+
+ for (; v!=stop; ++v) {
+ DOMElement* e = (*v)->getDOM();
+ if (e) {
+ DDF converted = convert(e, false);
+ if (!converted.isnull())
+ dest.add(converted);
+ }
+ else
+ log.warn("skipping XMLObject without a backing DOM");
+ }
+
+ return dest.integer() ? _decode(attr.release()) : nullptr;
+}
+
+DDF DOMAttributeDecoder::convert(DOMElement* e, bool nameit) const
+{
+ const XMLCh* nsURI;
+ const XMLCh* local;
+ map<pair<xstring,xstring>,string>::const_iterator mapping;
+ DDF obj = DDF(nullptr).structure();
+
+ if (nameit) {
+ // Name this structure.
+ nsURI = e->getNamespaceURI();
+ local = e->getLocalName();
+ mapping = m_tagMap.find(pair<xstring,xstring>(local,nsURI));
+ if (mapping == m_tagMap.end()) {
+ auto_ptr_char temp(local);
+ obj.name(temp.get());
+ }
+ else {
+ obj.name(mapping->second.c_str());
+ }
+ }
+
+ // Process non-xmlns attributes.
+ DOMNamedNodeMap* attrs = e->getAttributes();
+ for (XMLSize_t a = attrs->getLength(); a > 0; --a) {
+ DOMNode* attr = attrs->item(a-1);
+ nsURI = attr->getNamespaceURI();
+ if (XMLString::equals(nsURI, xmlconstants::XMLNS_NS))
+ continue;
+ local = attr->getLocalName();
+ mapping = m_tagMap.find(pair<xstring,xstring>(local, nsURI ? nsURI : &chNull));
+ if (mapping == m_tagMap.end()) {
+ auto_ptr_char temp(local);
+ obj.addmember(temp.get()).string(toUTF8(attr->getNodeValue(), true), false);
+ }
+ else {
+ obj.addmember(mapping->second.c_str()).string(toUTF8(attr->getNodeValue(), true), false);
+ }
+ }
+
+ DOMElement* child = XMLHelper::getFirstChildElement(e);
+ if (!child && e->hasChildNodes() && e->getFirstChild()->getNodeType() == DOMNode::TEXT_NODE) {
+ // Attach a _text member if a text node is present.
+ obj.addmember("_string").string(toUTF8(e->getFirstChild()->getTextContent(), true), false);
+ }
+ else {
+ while (child) {
+ // Convert the child element.
+ DDF converted = convert(child);
+ if (!converted.isnull()) {
+ // Now identify it and attach it.
+ if (obj[converted.name()].isnull()) {
+ // We're a new child, so just attach as a structure member.
+ obj.add(converted);
+ }
+ else if (obj[converted.name()].islist()) {
+ // We're already a repeating child, so add it to the list.
+ obj[converted.name()].add(converted);
+ }
+ else if (obj[converted.name()].isstruct()) {
+ // This is the complex case where we see a child for the second
+ // time and have to convert a structure member into a named list.
+ DDF newlist = DDF(converted.name()).list();
+ newlist.add(obj[converted.name()].remove());
+ newlist.add(converted);
+ obj.add(newlist);
+ }
+ }
+ child = XMLHelper::getNextSiblingElement(child);
+ }
+ }
+
+ // If we're empty, just delete.
+ if (obj.integer() == 0)
+ obj.destroy();
+ return obj;
+}