/** * 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. */ /** * shibsp/attribute/Attribute.cpp * * A resolved attribute. */ #include "internal.h" #include "exceptions.h" #include "SPConfig.h" #include "attribute/SimpleAttribute.h" #ifndef SHIBSP_LITE # include "attribute/AttributeDecoder.h" #endif #include "util/SPConstants.h" #include #include #include #include using namespace shibsp; using namespace xmltooling; using namespace std; namespace shibsp { 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); SHIBSP_DLLLOCAL Attribute* BinaryAttributeFactory(DDF& in); #ifndef SHIBSP_LITE SHIBSP_DLLLOCAL PluginManager::Factory StringAttributeDecoderFactory; SHIBSP_DLLLOCAL PluginManager::Factory ScopedAttributeDecoderFactory; SHIBSP_DLLLOCAL PluginManager::Factory NameIDAttributeDecoderFactory; SHIBSP_DLLLOCAL PluginManager::Factory NameIDFromScopedAttributeDecoderFactory; SHIBSP_DLLLOCAL PluginManager::Factory KeyInfoAttributeDecoderFactory; SHIBSP_DLLLOCAL PluginManager::Factory DOMAttributeDecoderFactory; SHIBSP_DLLLOCAL PluginManager::Factory XMLAttributeDecoderFactory; SHIBSP_DLLLOCAL PluginManager::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 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); static const XMLCh langAware[] = UNICODE_LITERAL_9(l,a,n,g,A,w,a,r,e); #endif }; #ifndef SHIBSP_LITE 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() { SPConfig& conf = SPConfig::getConfig(); conf.AttributeDecoderManager.registerFactory(StringAttributeDecoderType, StringAttributeDecoderFactory); 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::getCaseSensitive(e, true)), m_internal(XMLHelper::getAttrBool(e, false, internal)), m_langAware(XMLHelper::getAttrBool(e, false, langAware)), m_hashAlg(XMLHelper::getAttrString(e, nullptr, hashAlg)) { if (m_internal) { SPConfig::getConfig().deprecation().warn(" internal option"); } if (m_langAware) { SPConfig::getConfig().deprecation().warn(" langAware option"); } if (!m_hashAlg.empty()) { SPConfig::getConfig().deprecation().warn(" hashAlg option"); } } AttributeDecoder::~AttributeDecoder() { } 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 simple(new SimpleAttribute(attr->getAliases())); simple->setCaseSensitive(false); simple->setInternal(m_internal); vector& newdest = simple->getValues(); const vector& serialized = attr->getSerializedValues(); for (vector::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; } pair::const_iterator,vector::const_iterator> AttributeDecoder::valueRange( const GenericRequest* request, const vector& objects ) const { if (!m_langAware || !request || objects.empty()) { return make_pair(objects.begin(), objects.end()); } else if (request && request->startLangMatching()) { do { for (vector::const_iterator i = objects.begin(); i != objects.end(); ++i) { if (request->matchLang((*i)->getLang())) { return make_pair(i, i + 1); } } } while (request->continueLangMatching()); } return make_pair(objects.begin(), objects.begin() + 1); } #endif void shibsp::registerAttributeFactories() { Attribute::registerFactory("", SimpleAttributeFactory); Attribute::registerFactory("Simple", SimpleAttributeFactory); Attribute::registerFactory("Binary", BinaryAttributeFactory); Attribute::registerFactory("Scoped", ScopedAttributeFactory); Attribute::registerFactory("NameID", NameIDAttributeFactory); Attribute::registerFactory("Extensible", ExtensibleAttributeFactory); Attribute::registerFactory("XML", XMLAttributeFactory); } map 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& 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& Attribute::getAliases() const { return m_id; } vector& 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; } size_t Attribute::valueCount() const { return m_serialized.size(); } const vector& 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::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::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).", params(1,in.name())); return (i->second)(in); }