Change license header.
[shibboleth/cpp-sp.git] / shibsp / attribute / Attribute.cpp
index d4301e4..a97037a 100644 (file)
@@ -1,17 +1,21 @@
-/*
- *  Copyright 2001-2007 Internet2
+/**
+ * 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.
  *
- * Licensed 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
+ * 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
+ * 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.
+ * 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.
  */
 
 /**
@@ -21,6 +25,7 @@
  */
 
 #include "internal.h"
+#include "exceptions.h"
 #include "SPConfig.h"
 #ifndef SHIBSP_LITE
 # include "attribute/AttributeDecoder.h"
 #include "attribute/SimpleAttribute.h"
 #include "attribute/ScopedAttribute.h"
 #include "attribute/NameIDAttribute.h"
+#include "attribute/ExtensibleAttribute.h"
+#include "attribute/XMLAttribute.h"
 #include "util/SPConstants.h"
 
 #include <xercesc/util/XMLUniDefs.hpp>
+#include <xmltooling/security/SecurityHelper.h>
+#include <xmltooling/util/XMLHelper.h>
 
 using namespace shibsp;
 using namespace xmltooling;
 using namespace std;
 
 namespace shibsp {
-
-    SHIBSP_DLLLOCAL Attribute* SimpleAttributeFactory(DDF& in) {
-        return new SimpleAttribute(in);
-    }
-
-    SHIBSP_DLLLOCAL Attribute* ScopedAttributeFactory(DDF& in) {
-        return new ScopedAttribute(in);
-    }
-
-    SHIBSP_DLLLOCAL Attribute* NameIDAttributeFactory(DDF& in) {
-        return new NameIDAttribute(in);
-    }
+    SHIBSP_DLLLOCAL Attribute* SimpleAttributeFactory(DDF& in);
+    SHIBSP_DLLLOCAL Attribute* ScopedAttributeFactory(DDF& in);
+    SHIBSP_DLLLOCAL Attribute* NameIDAttributeFactory(DDF& in);
+    SHIBSP_DLLLOCAL Attribute* ExtensibleAttributeFactory(DDF& in);
+    SHIBSP_DLLLOCAL Attribute* XMLAttributeFactory(DDF& in);
 
 #ifndef SHIBSP_LITE
-    SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,QName,const DOMElement*>::Factory StringAttributeDecoderFactory;
-    SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,QName,const DOMElement*>::Factory ScopedAttributeDecoderFactory;
-    SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,QName,const DOMElement*>::Factory NameIDAttributeDecoderFactory;
-    SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,QName,const DOMElement*>::Factory NameIDFromScopedAttributeDecoderFactory;
+    SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory StringAttributeDecoderFactory;
+    SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory ScopedAttributeDecoderFactory;
+    SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory NameIDAttributeDecoderFactory;
+    SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory NameIDFromScopedAttributeDecoderFactory;
+    SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory KeyInfoAttributeDecoderFactory;
+    SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory DOMAttributeDecoderFactory;
+    SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory XMLAttributeDecoderFactory;
+    SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory Base64AttributeDecoderFactory;
 
     static const XMLCh _StringAttributeDecoder[] = UNICODE_LITERAL_22(S,t,r,i,n,g,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
     static const XMLCh _ScopedAttributeDecoder[] = UNICODE_LITERAL_22(S,c,o,p,e,d,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
     static const XMLCh _NameIDAttributeDecoder[] = UNICODE_LITERAL_22(N,a,m,e,I,D,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
     static const XMLCh _NameIDFromScopedAttributeDecoder[] = UNICODE_LITERAL_32(N,a,m,e,I,D,F,r,o,m,S,c,o,p,e,d,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
+    static const XMLCh _KeyInfoAttributeDecoder[] =UNICODE_LITERAL_23(K,e,y,I,n,f,o,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
+    static const XMLCh _DOMAttributeDecoder[] =    UNICODE_LITERAL_19(D,O,M,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
+    static const XMLCh _XMLAttributeDecoder[] =    UNICODE_LITERAL_19(X,M,L,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
+    static const XMLCh _Base64AttributeDecoder[] = {
+        chLatin_B, chLatin_a, chLatin_s, chLatin_e, chDigit_6, chDigit_4,
+        chLatin_A, chLatin_t, chLatin_t, chLatin_r, chLatin_i, chLatin_b, chLatin_u, chLatin_t, chLatin_e,
+        chLatin_D, chLatin_e, chLatin_c, chLatin_o, chLatin_d, chLatin_e, chLatin_r, chNull
+    };
 
     static const XMLCh caseSensitive[] =           UNICODE_LITERAL_13(c,a,s,e,S,e,n,s,i,t,i,v,e);
+    static const XMLCh hashAlg[] =                 UNICODE_LITERAL_7(h,a,s,h,A,l,g);
+    static const XMLCh internal[] =                UNICODE_LITERAL_8(i,n,t,e,r,n,a,l);
 #endif
 };
 
 #ifndef SHIBSP_LITE
-QName shibsp::StringAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _StringAttributeDecoder);
-QName shibsp::ScopedAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _ScopedAttributeDecoder);
-QName shibsp::NameIDAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _NameIDAttributeDecoder);
-QName shibsp::NameIDFromScopedAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _NameIDFromScopedAttributeDecoder);
+xmltooling::QName shibsp::StringAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _StringAttributeDecoder);
+xmltooling::QName shibsp::ScopedAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _ScopedAttributeDecoder);
+xmltooling::QName shibsp::NameIDAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _NameIDAttributeDecoder);
+xmltooling::QName shibsp::NameIDFromScopedAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _NameIDFromScopedAttributeDecoder);
+xmltooling::QName shibsp::KeyInfoAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _KeyInfoAttributeDecoder);
+xmltooling::QName shibsp::DOMAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _DOMAttributeDecoder);
+xmltooling::QName shibsp::XMLAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _XMLAttributeDecoder);
+xmltooling::QName shibsp::Base64AttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _Base64AttributeDecoder);
 
 void shibsp::registerAttributeDecoders()
 {
@@ -78,15 +98,47 @@ void shibsp::registerAttributeDecoders()
     conf.AttributeDecoderManager.registerFactory(ScopedAttributeDecoderType, ScopedAttributeDecoderFactory);
     conf.AttributeDecoderManager.registerFactory(NameIDAttributeDecoderType, NameIDAttributeDecoderFactory);
     conf.AttributeDecoderManager.registerFactory(NameIDFromScopedAttributeDecoderType, NameIDFromScopedAttributeDecoderFactory);
+    conf.AttributeDecoderManager.registerFactory(KeyInfoAttributeDecoderType, KeyInfoAttributeDecoderFactory);
+    conf.AttributeDecoderManager.registerFactory(DOMAttributeDecoderType, DOMAttributeDecoderFactory);
+    conf.AttributeDecoderManager.registerFactory(XMLAttributeDecoderType, XMLAttributeDecoderFactory);
+    conf.AttributeDecoderManager.registerFactory(Base64AttributeDecoderType, Base64AttributeDecoderFactory);
+}
+
+AttributeDecoder::AttributeDecoder(const DOMElement *e)
+    : m_caseSensitive(XMLHelper::getAttrBool(e, true, caseSensitive)),
+        m_internal(XMLHelper::getAttrBool(e, false, internal)),
+        m_hashAlg(XMLHelper::getAttrString(e, nullptr, hashAlg))
+{
 }
 
-AttributeDecoder::AttributeDecoder(const DOMElement *e) : m_caseSensitive(true)
+AttributeDecoder::~AttributeDecoder()
 {
-    if (e) {
-        const XMLCh* flag = e->getAttributeNS(NULL,caseSensitive);
-        if (flag && (*flag == chLatin_f || *flag == chDigit_0))
-            m_caseSensitive = false;
+}
+
+Attribute* AttributeDecoder::_decode(Attribute* attr) const
+{
+    if (attr) {
+        attr->setCaseSensitive(m_caseSensitive);
+        attr->setInternal(m_internal);
+
+        if (!m_hashAlg.empty()) {
+            // We turn the values into strings using the supplied hash algorithm and return a SimpleAttribute instead.
+            auto_ptr<SimpleAttribute> simple(new SimpleAttribute(attr->getAliases()));
+            simple->setCaseSensitive(false);
+            simple->setInternal(m_internal);
+            vector<string>& newdest = simple->getValues();
+            const vector<string>& serialized = attr->getSerializedValues();
+            for (vector<string>::const_iterator ser = serialized.begin(); ser != serialized.end(); ++ser) {
+                newdest.push_back(SecurityHelper::doHash(m_hashAlg.c_str(), ser->data(), ser->length()));
+                if (newdest.back().empty())
+                    newdest.pop_back();
+            }
+            delete attr;
+            return newdest.empty() ? nullptr : simple.release();
+        }
+
     }
+    return attr;
 }
 #endif
 
@@ -96,14 +148,136 @@ void shibsp::registerAttributeFactories()
     Attribute::registerFactory("Simple", SimpleAttributeFactory);
     Attribute::registerFactory("Scoped", ScopedAttributeFactory);
     Attribute::registerFactory("NameID", NameIDAttributeFactory);
+    Attribute::registerFactory("Extensible", ExtensibleAttributeFactory);
+    Attribute::registerFactory("XML", XMLAttributeFactory);
+}
+
+map<string,Attribute::AttributeFactory*> Attribute::m_factoryMap;
+
+void Attribute::registerFactory(const char* type, AttributeFactory* factory)
+{
+    m_factoryMap[type] = factory;
+}
+
+void Attribute::deregisterFactory(const char* type)
+{
+    m_factoryMap.erase(type);
+}
+
+void Attribute::deregisterFactories()
+{
+    m_factoryMap.clear();
+}
+
+Attribute::Attribute(const vector<string>& ids) : m_id(ids), m_caseSensitive(true), m_internal(false)
+{
+}
+
+Attribute::Attribute(DDF& in) : m_caseSensitive(in["case_insensitive"].isnull()), m_internal(!in["internal"].isnull())
+{
+    const char* id = in.first().name();
+    if (id && *id)
+        m_id.push_back(id);
+    else
+        throw AttributeException("No id found in marshalled attribute content.");
+    DDF aliases = in["aliases"];
+    if (aliases.islist()) {
+        DDF alias = aliases.first();
+        while (alias.isstring()) {
+            m_id.push_back(alias.string());
+            alias = aliases.next();
+        }
+    }
+}
+
+Attribute::~Attribute()
+{
+}
+
+const char* Attribute::getId() const
+{
+    return m_id.front().c_str();
+}
+
+const vector<string>& Attribute::getAliases() const
+{
+    return m_id;
+}
+
+vector<string>& Attribute::getAliases()
+{
+    return m_id;
+}
+
+void Attribute::setCaseSensitive(bool caseSensitive)
+{
+    m_caseSensitive = caseSensitive;
+}
+
+void Attribute::setInternal(bool internal)
+{
+    m_internal = internal;
+}
+
+bool Attribute::isCaseSensitive() const
+{
+    return m_caseSensitive;
+}
+
+bool Attribute::isInternal() const
+{
+    return m_internal;
 }
 
-std::map<std::string,Attribute::AttributeFactory*> Attribute::m_factoryMap;
+size_t Attribute::valueCount() const
+{
+    return m_serialized.size();
+}
+
+const vector<string>& Attribute::getSerializedValues() const
+{
+    return m_serialized;
+}
+
+const char* Attribute::getString(size_t index) const
+{
+    return m_serialized[index].c_str();
+}
+
+const char* Attribute::getScope(size_t index) const
+{
+    return nullptr;
+}
+
+void Attribute::removeValue(size_t index)
+{
+    if (index < m_serialized.size())
+        m_serialized.erase(m_serialized.begin() + index);
+}
+
+DDF Attribute::marshall() const
+{
+    DDF ddf(nullptr);
+    ddf.structure().addmember(m_id.front().c_str()).list();
+    if (!m_caseSensitive)
+        ddf.addmember("case_insensitive");
+    if (m_internal)
+        ddf.addmember("internal");
+    if (m_id.size() > 1) {
+        DDF alias;
+        DDF aliases = ddf.addmember("aliases").list();
+        for (std::vector<std::string>::const_iterator a = m_id.begin() + 1; a != m_id.end(); ++a) {
+            alias = DDF(nullptr).string(a->c_str());
+            aliases.add(alias);
+        }
+    }
+    return ddf;
+}
 
 Attribute* Attribute::unmarshall(DDF& in)
 {
     map<string,AttributeFactory*>::const_iterator i = m_factoryMap.find(in.name() ? in.name() : "");
     if (i == m_factoryMap.end())
-        throw AttributeException("No registered factory for Attribute of type ($1).", xmltooling::params(1,in.name()));
+        throw AttributeException("No registered factory for Attribute of type ($1).", params(1,in.name()));
     return (i->second)(in);
 }