SSPCPP-341 - Case folding resolver plugin
authorScott Cantor <cantor.2@osu.edu>
Tue, 10 Apr 2012 20:41:16 +0000 (20:41 +0000)
committerScott Cantor <cantor.2@osu.edu>
Tue, 10 Apr 2012 20:41:16 +0000 (20:41 +0000)
plugins/CaseFoldingAttributeResolver.cpp [new file with mode: 0644]
plugins/Makefile.am
plugins/TransformAttributeResolver.cpp
plugins/plugins.cpp
plugins/plugins.vcxproj
plugins/plugins.vcxproj.filters

diff --git a/plugins/CaseFoldingAttributeResolver.cpp b/plugins/CaseFoldingAttributeResolver.cpp
new file mode 100644 (file)
index 0000000..34ded99
--- /dev/null
@@ -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 <algorithm>
+#include <shibsp/exceptions.h>
+#include <shibsp/SessionCache.h>
+#include <shibsp/attribute/SimpleAttribute.h>
+#include <shibsp/attribute/resolver/AttributeResolver.h>
+#include <shibsp/attribute/resolver/ResolutionContext.h>
+#include <xmltooling/XMLToolingConfig.h>
+#include <xmltooling/util/XMLHelper.h>
+#include <xercesc/util/XMLUniDefs.hpp>
+
+using namespace shibsp;
+using namespace xmltooling;
+using namespace xercesc;
+using namespace std;
+
+namespace shibsp {
+
+    class SHIBSP_DLLLOCAL FoldingContext : public ResolutionContext
+    {
+    public:
+        FoldingContext(const vector<Attribute*>* attributes) : m_inputAttributes(attributes) {
+        }
+
+        ~FoldingContext() {
+            for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup<Attribute>());
+        }
+
+        const vector<Attribute*>* getInputAttributes() const {
+            return m_inputAttributes;
+        }
+        vector<Attribute*>& getResolvedAttributes() {
+            return m_attributes;
+        }
+        vector<opensaml::Assertion*>& getResolvedAssertions() {
+            return m_assertions;
+        }
+
+    private:
+        const vector<Attribute*>* m_inputAttributes;
+        vector<Attribute*> m_attributes;
+        static vector<opensaml::Assertion*> 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<const opensaml::Assertion*>* tokens=nullptr,
+            const vector<Attribute*>* 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<const opensaml::Assertion*>* tokens=nullptr,
+            const vector<Attribute*>* 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<string>& 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<string> 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<opensaml::Assertion*> 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<FoldingContext&>(ctx);
+    if (!fctx.getInputAttributes())
+        return;
+
+    auto_ptr<SimpleAttribute> destwrapper;
+
+    for (vector<Attribute*>::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<SimpleAttribute*>(*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<XMLCh> valjanitor(srcval);
+                    (m_direction == _up) ? XMLString::upperCase(srcval) : XMLString::lowerCase(srcval);
+                    auto_arrayptr<char> 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();
+    }
+}
index 230bf4b..1c03b16 100644 (file)
@@ -11,6 +11,7 @@ common_sources = \
 
 plugins_la_SOURCES = \
        ${common_sources} \
+    CaseFoldingAttributeResolver.cpp \
        GSSAPIAttributeExtractor.cpp \
     TemplateAttributeResolver.cpp \
     TransformAttributeResolver.cpp
index f620dc0..1856d3e 100644 (file)
@@ -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<XMLCh> srcval(fromUTF8((*a)->getSerializedValues()[i].c_str()));
                 try {
+                    auto_arrayptr<XMLCh> srcval(fromUTF8((*a)->getSerializedValues()[i].c_str()));
                     XMLCh* destval = r->get<1>()->replace(srcval.get(), r->get<2>());
                     if (destval) {
                         auto_arrayptr<char> narrow(toUTF8(destval));
index ead4f8e..323f7d4 100644 (file)
@@ -46,6 +46,8 @@ namespace shibsp {
 #endif
     PluginManager<AttributeResolver,string,const DOMElement*>::Factory TemplateAttributeResolverFactory;
     PluginManager<AttributeResolver,string,const DOMElement*>::Factory TransformAttributeResolverFactory;
+    PluginManager<AttributeResolver,string,const DOMElement*>::Factory UpperCaseAttributeResolverFactory;
+    PluginManager<AttributeResolver,string,const DOMElement*>::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
 }
 
index e73adde..c5c78cd 100644 (file)
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClCompile Include="CaseFoldingAttributeResolver.cpp" />
     <ClCompile Include="GSSAPIAttributeExtractor.cpp" />
     <ClCompile Include="plugins.cpp" />
     <ClCompile Include="TemplateAttributeResolver.cpp" />
index f126958..f47d1e8 100644 (file)
@@ -5,6 +5,7 @@
     <ClCompile Include="plugins.cpp" />
     <ClCompile Include="TransformAttributeResolver.cpp" />
     <ClCompile Include="TemplateAttributeResolver.cpp" />
+    <ClCompile Include="CaseFoldingAttributeResolver.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="internal.h" />