From: Scott Cantor Date: Tue, 10 Apr 2012 20:41:16 +0000 (+0000) Subject: SSPCPP-341 - Case folding resolver plugin X-Git-Tag: 2.5.0~139 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=shibboleth%2Fcpp-sp.git;a=commitdiff_plain;h=dab23c7b89f186b0683339615efbdc8cfe4492fa SSPCPP-341 - Case folding resolver plugin --- diff --git a/plugins/CaseFoldingAttributeResolver.cpp b/plugins/CaseFoldingAttributeResolver.cpp new file mode 100644 index 0000000..34ded99 --- /dev/null +++ b/plugins/CaseFoldingAttributeResolver.cpp @@ -0,0 +1,221 @@ +/** + * 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. + */ + +/** + * CaseFoldingAttributeResolver.cpp + * + * Attribute Resolver plugins for upcasing and downcasing. + */ + +#include "internal.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace shibsp; +using namespace xmltooling; +using namespace xercesc; +using namespace std; + +namespace shibsp { + + class SHIBSP_DLLLOCAL FoldingContext : public ResolutionContext + { + public: + FoldingContext(const vector* attributes) : m_inputAttributes(attributes) { + } + + ~FoldingContext() { + for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup()); + } + + const vector* getInputAttributes() const { + return m_inputAttributes; + } + vector& getResolvedAttributes() { + return m_attributes; + } + vector& getResolvedAssertions() { + return m_assertions; + } + + private: + const vector* m_inputAttributes; + vector m_attributes; + static vector m_assertions; // empty dummy + }; + + + class SHIBSP_DLLLOCAL CaseFoldingAttributeResolver : public AttributeResolver + { + public: + enum case_t { + _up, + _down + }; + + CaseFoldingAttributeResolver(const DOMElement* e, case_t direction); + virtual ~CaseFoldingAttributeResolver() {} + + Lockable* lock() { + return this; + } + void unlock() { + } + + ResolutionContext* createResolutionContext( + const Application& application, + const opensaml::saml2md::EntityDescriptor* issuer, + const XMLCh* protocol, + const opensaml::saml2::NameID* nameid=nullptr, + const XMLCh* authncontext_class=nullptr, + const XMLCh* authncontext_decl=nullptr, + const vector* tokens=nullptr, + const vector* attributes=nullptr + ) const { + // Make sure new method gets run. + return createResolutionContext(application, nullptr, issuer, protocol, nameid, authncontext_class, authncontext_decl, tokens, attributes); + } + + ResolutionContext* createResolutionContext( + const Application& application, + const GenericRequest* request, + const opensaml::saml2md::EntityDescriptor* issuer, + const XMLCh* protocol, + const opensaml::saml2::NameID* nameid=nullptr, + const XMLCh* authncontext_class=nullptr, + const XMLCh* authncontext_decl=nullptr, + const vector* tokens=nullptr, + const vector* attributes=nullptr + ) const { + return new FoldingContext(attributes); + } + + ResolutionContext* createResolutionContext(const Application& application, const Session& session) const { + return new FoldingContext(&session.getAttributes()); + } + + void resolveAttributes(ResolutionContext& ctx) const; + + void getAttributeIds(vector& attributes) const { + if (!m_dest.empty() && !m_dest.front().empty()) + attributes.push_back(m_dest.front()); + } + + private: + Category& m_log; + case_t m_direction; + string m_source; + vector m_dest; + }; + + static const XMLCh dest[] = UNICODE_LITERAL_4(d,e,s,t); + static const XMLCh source[] = UNICODE_LITERAL_6(s,o,u,r,c,e); + + AttributeResolver* SHIBSP_DLLLOCAL UpperCaseAttributeResolverFactory(const DOMElement* const & e) + { + return new CaseFoldingAttributeResolver(e, CaseFoldingAttributeResolver::_up); + } + + AttributeResolver* SHIBSP_DLLLOCAL LowerCaseAttributeResolverFactory(const DOMElement* const & e) + { + return new CaseFoldingAttributeResolver(e, CaseFoldingAttributeResolver::_down); + } +}; + +vector FoldingContext::m_assertions; + +CaseFoldingAttributeResolver::CaseFoldingAttributeResolver(const DOMElement* e, case_t direction) + : m_log(Category::getInstance(SHIBSP_LOGCAT".AttributeResolver.CaseFolding")), + m_direction(direction), + m_source(XMLHelper::getAttrString(e, nullptr, source)), + m_dest(1, XMLHelper::getAttrString(e, nullptr, dest)) +{ + if (m_source.empty()) + throw ConfigurationException("CaseFolding AttributeResolver requires source attribute."); +} + + +void CaseFoldingAttributeResolver::resolveAttributes(ResolutionContext& ctx) const +{ + FoldingContext& fctx = dynamic_cast(ctx); + if (!fctx.getInputAttributes()) + return; + + auto_ptr destwrapper; + + for (vector::const_iterator a = fctx.getInputAttributes()->begin(); a != fctx.getInputAttributes()->end(); ++a) { + if (m_source != (*a)->getId() || (*a)->valueCount() == 0) { + continue; + } + + SimpleAttribute* dest = nullptr; + if (m_dest.empty() || m_dest.front().empty()) { + // Can we transform in-place? + dest = dynamic_cast(*a); + if (!dest) { + m_log.warn("can't %scase non-simple attribute (%s) 'in place'", (m_direction==_up ? "up" : "down"), m_source.c_str()); + continue; + } + m_log.debug("applying in-place transform to source attribute (%s)", m_source.c_str()); + } + else if (!destwrapper.get()) { + // Create a destination attribute. + destwrapper.reset(new SimpleAttribute(m_dest)); + m_log.debug("applying transform from source attribute (%s) to dest attribute (%s)", m_source.c_str(), m_dest.front().c_str()); + } + + for (size_t i = 0; i < (*a)->valueCount(); ++i) { + try { + XMLCh* srcval = fromUTF8((*a)->getSerializedValues()[i].c_str()); + if (srcval) { + auto_arrayptr valjanitor(srcval); + (m_direction == _up) ? XMLString::upperCase(srcval) : XMLString::lowerCase(srcval); + auto_arrayptr narrow(toUTF8(srcval)); + if (dest) { + // Modify in place. + dest->getValues()[i] = narrow.get(); + } + else { + // Add to new object. + destwrapper->getValues().push_back(narrow.get()); + } + } + } + catch (XMLException& ex) { + auto_ptr_char msg(ex.getMessage()); + m_log.error("caught error performing conversion: %s", msg.get()); + } + } + } + + // Save off new object. + if (destwrapper.get()) { + ctx.getResolvedAttributes().push_back(destwrapper.get()); + destwrapper.release(); + } +} diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 230bf4b..1c03b16 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -11,6 +11,7 @@ common_sources = \ plugins_la_SOURCES = \ ${common_sources} \ + CaseFoldingAttributeResolver.cpp \ GSSAPIAttributeExtractor.cpp \ TemplateAttributeResolver.cpp \ TransformAttributeResolver.cpp diff --git a/plugins/TransformAttributeResolver.cpp b/plugins/TransformAttributeResolver.cpp index f620dc0..1856d3e 100644 --- a/plugins/TransformAttributeResolver.cpp +++ b/plugins/TransformAttributeResolver.cpp @@ -223,8 +223,8 @@ void TransformAttributeResolver::resolveAttributes(ResolutionContext& ctx) const m_log.debug("applying transform from source attribute (%s) to dest attribute (%s)", m_source.c_str(), r->get<0>().c_str()); for (size_t i = 0; i < (*a)->valueCount(); ++i) { - auto_arrayptr srcval(fromUTF8((*a)->getSerializedValues()[i].c_str())); try { + auto_arrayptr srcval(fromUTF8((*a)->getSerializedValues()[i].c_str())); XMLCh* destval = r->get<1>()->replace(srcval.get(), r->get<2>()); if (destval) { auto_arrayptr narrow(toUTF8(destval)); diff --git a/plugins/plugins.cpp b/plugins/plugins.cpp index ead4f8e..323f7d4 100644 --- a/plugins/plugins.cpp +++ b/plugins/plugins.cpp @@ -46,6 +46,8 @@ namespace shibsp { #endif PluginManager::Factory TemplateAttributeResolverFactory; PluginManager::Factory TransformAttributeResolverFactory; + PluginManager::Factory UpperCaseAttributeResolverFactory; + PluginManager::Factory LowerCaseAttributeResolverFactory; }; extern "C" int PLUGINS_EXPORTS xmltooling_extension_init(void*) @@ -60,6 +62,8 @@ extern "C" int PLUGINS_EXPORTS xmltooling_extension_init(void*) #endif conf.AttributeResolverManager.registerFactory("Template", TemplateAttributeResolverFactory); conf.AttributeResolverManager.registerFactory("Transform", TransformAttributeResolverFactory); + conf.AttributeResolverManager.registerFactory("UpperCase", UpperCaseAttributeResolverFactory); + conf.AttributeResolverManager.registerFactory("LowerCase", LowerCaseAttributeResolverFactory); return 0; // signal success } diff --git a/plugins/plugins.vcxproj b/plugins/plugins.vcxproj index e73adde..c5c78cd 100644 --- a/plugins/plugins.vcxproj +++ b/plugins/plugins.vcxproj @@ -175,6 +175,7 @@ + diff --git a/plugins/plugins.vcxproj.filters b/plugins/plugins.vcxproj.filters index f126958..f47d1e8 100644 --- a/plugins/plugins.vcxproj.filters +++ b/plugins/plugins.vcxproj.filters @@ -5,6 +5,7 @@ +