[shibboleth-sp2] 45/89: SSPCPP-528 - AttributeQuery Handler

Ferenc Wágner wferi at moszumanska.debian.org
Thu Sep 1 09:24:07 UTC 2016


This is an automated email from the git hooks/post-receive script.

wferi pushed a commit to branch master
in repository shibboleth-sp2.

commit a65d5c54cd481f67d9d9a6df3739fb9dac125385
Author: Scott Cantor <cantor.2 at osu.edu>
Date:   Mon Jun 6 16:50:54 2016 -0400

    SSPCPP-528 - AttributeQuery Handler
    
    https://issues.shibboleth.net/jira/browse/SSPCPP-528
---
 Projects/vc10/plugins/plugins-lite.vcxproj    |   6 +-
 Projects/vc10/plugins/plugins.vcxproj         |   6 +-
 Projects/vc10/plugins/plugins.vcxproj.filters |  21 +-
 Projects/vc14/plugins/plugins-lite.vcxproj    |   1 +
 Projects/vc14/plugins/plugins.vcxproj         |   1 +
 Projects/vc14/plugins/plugins.vcxproj.filters |   1 +
 doc/CREDITS.txt                               |   2 +
 doc/NOTICE.txt                                |   3 +-
 plugins/AttributeResolverHandler.cpp          | 518 ++++++++++++++++++++++++++
 plugins/Makefile.am                           |   1 +
 plugins/plugins.cpp                           |   3 +
 11 files changed, 546 insertions(+), 17 deletions(-)

diff --git a/Projects/vc10/plugins/plugins-lite.vcxproj b/Projects/vc10/plugins/plugins-lite.vcxproj
index dece135..18cc3c5 100644
--- a/Projects/vc10/plugins/plugins-lite.vcxproj
+++ b/Projects/vc10/plugins/plugins-lite.vcxproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup Label="ProjectConfigurations">
     <ProjectConfiguration Include="Debug|Win32">
@@ -70,7 +70,6 @@
     <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)\..\..\Build\VC10\$(Platform)\$(Configuration)\</OutDir>
     <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)\..\..\Build\VC10\\$(Configuration)\</OutDir>
     <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)\..\..\Build\VC10\\$(Configuration)\</OutDir>
-
     <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(ProjectName)-$(Configuration)\</IntDir>
     <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>
     <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
@@ -183,6 +182,7 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClCompile Include="..\..\..\plugins\AttributeResolverHandler.cpp" />
     <ClCompile Include="..\..\..\plugins\plugins.cpp" />
     <ClCompile Include="..\..\..\plugins\TimeAccessControl.cpp" />
   </ItemGroup>
@@ -205,4 +205,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
-</Project>
+</Project>
\ No newline at end of file
diff --git a/Projects/vc10/plugins/plugins.vcxproj b/Projects/vc10/plugins/plugins.vcxproj
index 80d23e1..76b5798 100644
--- a/Projects/vc10/plugins/plugins.vcxproj
+++ b/Projects/vc10/plugins/plugins.vcxproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup Label="ProjectConfigurations">
     <ProjectConfiguration Include="Debug|Win32">
@@ -70,7 +70,6 @@
     <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)\..\..\Build\VC10\$(Platform)\$(Configuration)\</OutDir>
     <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)\..\..\Build\VC10\\$(Configuration)\</OutDir>
     <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)\..\..\Build\VC10\\$(Configuration)\</OutDir>
-
     <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>
     <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>
     <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
@@ -181,6 +180,7 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClCompile Include="..\..\..\plugins\AttributeResolverHandler.cpp" />
     <ClCompile Include="..\..\..\plugins\CaseFoldingAttributeResolver.cpp" />
     <ClCompile Include="..\..\..\plugins\GSSAPIAttributeExtractor.cpp" />
     <ClCompile Include="..\..\..\plugins\plugins.cpp" />
@@ -207,4 +207,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
-</Project>
+</Project>
\ No newline at end of file
diff --git a/Projects/vc10/plugins/plugins.vcxproj.filters b/Projects/vc10/plugins/plugins.vcxproj.filters
index 09299f3..bf5418c 100644
--- a/Projects/vc10/plugins/plugins.vcxproj.filters
+++ b/Projects/vc10/plugins/plugins.vcxproj.filters
@@ -1,21 +1,22 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
-    <ClCompile Include="GSSAPIAttributeExtractor.cpp" />
-    <ClCompile Include="plugins.cpp" />
-    <ClCompile Include="TransformAttributeResolver.cpp" />
-    <ClCompile Include="TemplateAttributeResolver.cpp" />
-    <ClCompile Include="CaseFoldingAttributeResolver.cpp" />
-    <ClCompile Include="TimeAccessControl.cpp" />
+    <ClCompile Include="..\..\..\plugins\CaseFoldingAttributeResolver.cpp" />
+    <ClCompile Include="..\..\..\plugins\GSSAPIAttributeExtractor.cpp" />
+    <ClCompile Include="..\..\..\plugins\plugins.cpp" />
+    <ClCompile Include="..\..\..\plugins\TemplateAttributeResolver.cpp" />
+    <ClCompile Include="..\..\..\plugins\TimeAccessControl.cpp" />
+    <ClCompile Include="..\..\..\plugins\TransformAttributeResolver.cpp" />
+    <ClCompile Include="..\..\..\plugins\AttributeResolverHandler.cpp" />
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="internal.h" />
-    <ClInclude Include="resource.h" />
+    <ClInclude Include="..\..\..\plugins\internal.h" />
+    <ClInclude Include="..\..\..\plugins\resource.h" />
   </ItemGroup>
   <ItemGroup>
-    <None Include="Makefile.am" />
+    <None Include="..\..\..\plugins\Makefile.am" />
   </ItemGroup>
   <ItemGroup>
-    <ResourceCompile Include="plugins.rc" />
+    <ResourceCompile Include="..\..\..\plugins\plugins.rc" />
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/Projects/vc14/plugins/plugins-lite.vcxproj b/Projects/vc14/plugins/plugins-lite.vcxproj
index e81749b..e16b35e 100644
--- a/Projects/vc14/plugins/plugins-lite.vcxproj
+++ b/Projects/vc14/plugins/plugins-lite.vcxproj
@@ -190,6 +190,7 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClCompile Include="..\..\..\plugins\AttributeResolverHandler.cpp" />
     <ClCompile Include="..\..\..\plugins\plugins.cpp" />
     <ClCompile Include="..\..\..\plugins\TimeAccessControl.cpp" />
   </ItemGroup>
diff --git a/Projects/vc14/plugins/plugins.vcxproj b/Projects/vc14/plugins/plugins.vcxproj
index 55cb877..0425444 100644
--- a/Projects/vc14/plugins/plugins.vcxproj
+++ b/Projects/vc14/plugins/plugins.vcxproj
@@ -188,6 +188,7 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClCompile Include="..\..\..\plugins\AttributeResolverHandler.cpp" />
     <ClCompile Include="..\..\..\plugins\CaseFoldingAttributeResolver.cpp" />
     <ClCompile Include="..\..\..\plugins\GSSAPIAttributeExtractor.cpp" />
     <ClCompile Include="..\..\..\plugins\plugins.cpp" />
diff --git a/Projects/vc14/plugins/plugins.vcxproj.filters b/Projects/vc14/plugins/plugins.vcxproj.filters
index 6f1c71d..bf5418c 100644
--- a/Projects/vc14/plugins/plugins.vcxproj.filters
+++ b/Projects/vc14/plugins/plugins.vcxproj.filters
@@ -7,6 +7,7 @@
     <ClCompile Include="..\..\..\plugins\TemplateAttributeResolver.cpp" />
     <ClCompile Include="..\..\..\plugins\TimeAccessControl.cpp" />
     <ClCompile Include="..\..\..\plugins\TransformAttributeResolver.cpp" />
+    <ClCompile Include="..\..\..\plugins\AttributeResolverHandler.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\..\plugins\internal.h" />
diff --git a/doc/CREDITS.txt b/doc/CREDITS.txt
index 4574341..f54340d 100644
--- a/doc/CREDITS.txt
+++ b/doc/CREDITS.txt
@@ -61,6 +61,8 @@ Additional thanks to:
     
     National Research Council of Canada
 
+    National Institute of Informatics in Japan
+
     Barbara Jenson (CMU), Parviz Dousti (CMU), Tom Dopirak (CMU), 
       and Sridhar Muppidi (IBM/Tivoli); for helping to develop 
       the initial Shibboleth prototype
diff --git a/doc/NOTICE.txt b/doc/NOTICE.txt
index 0481820..6be96e4 100644
--- a/doc/NOTICE.txt
+++ b/doc/NOTICE.txt
@@ -10,8 +10,9 @@ for use in the OpenSSL Toolkit. (http://www.openssl.org/).
 This project uses libraries covered by the Lesser GNU Public License.
 Source code for these libraries is available on request.
 
-This product includes software developed, copyrighted, and contributed by:
+This product includes software developed, copyrighted, and/or contributed by:
 
 The Ohio State University
 The National Research Council of Canada
 The Danish CLARIN Consortium
+National Institute of Informatics in Japan
\ No newline at end of file
diff --git a/plugins/AttributeResolverHandler.cpp b/plugins/AttributeResolverHandler.cpp
new file mode 100644
index 0000000..554b3a0
--- /dev/null
+++ b/plugins/AttributeResolverHandler.cpp
@@ -0,0 +1,518 @@
+/**
+ * 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.
+ */
+
+/**
+ * AttributeResolverHandler.cpp
+ *
+ * Handler that runs the attribute resolver machinery and outputs the results directly.
+ */
+
+#if defined (_MSC_VER) || defined(__BORLANDC__)
+# include "config_win32.h"
+#else
+# include "config.h"
+#endif
+
+#include "internal.h"
+
+#include <shibsp/Application.h>
+#include <shibsp/exceptions.h>
+#include <shibsp/ServiceProvider.h>
+#include <shibsp/SPConfig.h>
+#include <shibsp/SPRequest.h>
+#include <shibsp/handler/SecuredHandler.h>
+#include <shibsp/handler/RemotedHandler.h>
+
+#include <boost/scoped_ptr.hpp>
+
+#ifndef SHIBSP_LITE
+#include <shibsp/attribute/Attribute.h>
+#include <shibsp/attribute/filtering/AttributeFilter.h>
+#include <shibsp/attribute/filtering/BasicFilteringContext.h>
+#include <shibsp/attribute/resolver/AttributeExtractor.h>
+#include <shibsp/attribute/resolver/AttributeResolver.h>
+#include <shibsp/attribute/resolver/ResolutionContext.h>
+#include <shibsp/metadata/MetadataProviderCriteria.h>
+
+#include <saml/exceptions.h>
+#include <saml/saml1/core/Assertions.h>
+#include <saml/saml2/core/Assertions.h>
+#include <saml/saml2/metadata/Metadata.h>
+#include <saml/saml2/metadata/MetadataProvider.h>
+#include <xmltooling/XMLToolingConfig.h>
+#include <xmltooling/util/ParserPool.h>
+#include <xmltooling/util/XMLHelper.h>
+#include <xercesc/util/XMLUniDefs.hpp>
+#include <boost/iterator/indirect_iterator.hpp>
+#endif
+
+using namespace std;
+using namespace shibsp;
+using namespace xmltooling;
+using namespace xercesc;
+using namespace boost;
+
+#ifndef SHIBSP_LITE
+using namespace opensaml::saml2md;
+using namespace opensaml;
+#endif
+
+namespace shibsp {
+
+#if defined (_MSC_VER)
+    #pragma warning( push )
+    #pragma warning( disable : 4250 )
+#endif
+
+    class SHIBSP_DLLLOCAL AttributeResolverHandler : public SecuredHandler, public RemotedHandler
+    {
+    public:
+        AttributeResolverHandler(const DOMElement* e, const char* appId);
+        virtual ~AttributeResolverHandler() {}
+
+        pair<bool,long> run(SPRequest& request, bool isHandler=true) const;
+        void receive(DDF& in, ostream& out);
+
+    private:
+        pair<bool,long> processMessage(
+            const Application& application,
+            const HTTPRequest& httpRequest,
+            HTTPResponse& httpResponse
+            ) const;
+
+#ifndef SHIBSP_LITE
+        ResolutionContext* resolveAttributes(
+            const Application& application,
+            const GenericRequest* request,
+            const RoleDescriptor* issuer,
+            const XMLCh* protocol,
+            const saml1::NameIdentifier* v1nameid,
+            const saml2::NameID* nameid
+            ) const;
+
+        ostream& buildJSON(ostream& os, vector<shibsp::Attribute*>& attributes) const;
+
+        string m_encoding;
+#endif
+    };
+
+#if defined (_MSC_VER)
+    #pragma warning( pop )
+#endif
+
+    Handler* SHIBSP_DLLLOCAL AttributeResolverHandlerFactory(const pair<const DOMElement*,const char*>& p)
+    {
+        return new AttributeResolverHandler(p.first, p.second);
+    }
+
+};
+
+#ifndef SHIBSP_LITE
+
+namespace {
+    class SHIBSP_DLLLOCAL DummyContext : public shibsp::ResolutionContext
+    {
+    public:
+        DummyContext(const vector<Attribute*>& attributes) : m_attributes(attributes) {
+        }
+
+        virtual ~DummyContext() {
+            for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup<Attribute>());
+        }
+
+        vector<Attribute*>& getResolvedAttributes() {
+            return m_attributes;
+        }
+        vector<Assertion*>& getResolvedAssertions() {
+            return m_tokens;
+        }
+
+    private:
+        vector<Attribute*> m_attributes;
+        static vector<Assertion*> m_tokens; // never any tokens, so just share an empty vector
+    };
+
+    static ostream& json_safe(ostream& os, const char* buf)
+    {
+        os << '"';
+        for (; *buf; ++buf) {
+            switch (*buf) {
+                case '\\':
+                case '"':
+                    os << '\\';
+                    os << *buf;
+                    break;
+                case '\b':
+                    os << "\\b";
+                    break;
+                case '\t':
+                    os << "\\t";
+                    break;
+                case '\n':
+                    os << "\\n";
+                    break;
+                case '\f':
+                    os << "\\f";
+                    break;
+                case '\r':
+                    os << "\\r";
+                    break;
+                default:
+                    os << *buf;
+            }
+        }
+        os << '"';
+        return os;
+    }
+};
+
+vector<Assertion*> DummyContext::m_tokens;
+
+#endif
+
+AttributeResolverHandler::AttributeResolverHandler(const DOMElement* e, const char* appId)
+        : SecuredHandler(e, Category::getInstance(SHIBSP_LOGCAT".AttributeResolverHandler"), "acl", "127.0.0.1 ::1")
+{
+    pair<bool,const char*> prop = getString("Location");
+    if (!prop.first)
+        throw ConfigurationException("AttributeQuery handler requires Location property.");
+    string address(appId);
+    address += prop.second;
+    setAddress(address.c_str());
+
+#ifndef SHIBSP_LITE
+    pair<bool, const char*> encoding = getString("encoding");
+    m_encoding = encoding.first ? encoding.second : "";
+#endif
+}
+
+pair<bool,long> AttributeResolverHandler::run(SPRequest& request, bool isHandler) const
+{
+    // Check ACL in base class.
+    pair<bool,long> ret = SecuredHandler::run(request, isHandler);
+    if (ret.first)
+        return ret;
+
+    request.setResponseHeader("Expires","Wed, 01 Jan 1997 12:00:00 GMT");
+    request.setResponseHeader("Cache-Control","private,no-store,no-cache,max-age=0");
+    request.setContentType("application/json; charset=utf-8");
+    try {
+        if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) {
+            // When out of process, we run natively and directly process the message.
+            return processMessage(request.getApplication(), request, request);
+        }
+        else {
+            // When not out of process, we remote all the message processing.
+            DDF out,in = wrap(request);
+            DDFJanitor jin(in), jout(out);
+            out=request.getServiceProvider().getListenerService()->send(in);
+            return unwrap(request, out);
+        }
+    }
+    catch (std::exception& ex) {
+        m_log.error("error while processing request: %s", ex.what());
+        istringstream msg("{}");
+        return make_pair(true, request.sendError(msg));
+    }
+}
+
+void AttributeResolverHandler::receive(DDF& in, ostream& out)
+{
+    // Find application.
+    const char* aid = in["application_id"].string();
+    const Application* app = aid ? SPConfig::getConfig().getServiceProvider()->getApplication(aid) : nullptr;
+    if (!app) {
+        // Something's horribly wrong.
+        m_log.error("couldn't find application (%s) for AttributeQuery request", aid ? aid : "(missing)");
+        throw ConfigurationException("Unable to locate application for request, deleted?");
+    }
+
+    // Wrap a response shim.
+    DDF ret(nullptr);
+    DDFJanitor jout(ret);
+    scoped_ptr<HTTPRequest> req(getRequest(in));
+    scoped_ptr<HTTPResponse> resp(getResponse(ret));
+
+    // Since we're remoted, the result should either be a throw, a false/0 return,
+    // which we just return as an empty structure, or a response/redirect,
+    // which we capture in the facade and send back.
+    try {
+        processMessage(*app, *req, *resp);
+    }
+    catch (std::exception& ex) {
+        m_log.error("raising exception: %s", ex.what());
+        throw;
+    }
+    out << ret;
+}
+
+pair<bool,long> AttributeResolverHandler::processMessage(
+    const Application& application, const HTTPRequest& httpRequest, HTTPResponse& httpResponse
+    ) const
+{
+#ifndef SHIBSP_LITE
+    m_log.debug("processing status request");
+    m_log.debug("request URL: %s", httpRequest.getRequestURL());
+
+    const char* param_protocol = httpRequest.getParameter("protocol");
+    const char* param_issuer   = httpRequest.getParameter("entityID");
+    const char* param_format   = httpRequest.getParameter("format");
+    const char* param_nameid   = httpRequest.getParameter("nameId");
+
+    m_log.debug("protocol = %s, entityID = %s, format = %s, name = %s",
+                param_protocol, param_issuer, param_format, param_nameid);
+
+    stringstream msg;
+
+    if (!param_nameid || !*param_nameid) {
+        m_log.error("AttributeQuery Handler requires nameId parameter");
+        msg << "{}";
+        return make_pair(true, httpResponse.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_BADREQUEST));
+    }
+
+    const auto_ptr_XMLCh issuer(param_issuer);
+    const auto_ptr_XMLCh nameid(param_nameid);
+    const auto_ptr_XMLCh format(param_format);
+
+    if (param_protocol) {
+        if (strcmp(param_protocol, "SAML2.0") == 0)
+            param_protocol = "urn:oasis:names:tc:SAML:2.0:protocol"; // samlconstants::SAML20P_NS;
+        else if (strcmp(param_protocol, "SAML1.1") == 0)
+            param_protocol = "urn:oasis:names:tc:SAML:1.1:protocol"; // samlconstants::SAML11_PROTOCOL_ENUM;
+        else if (strcmp(param_protocol, "SAML1.0") == 0)
+            param_protocol = "urn:oasis:names:tc:SAML:1.0:protocol"; // samlconstants::SAML10_PROTOCOL_ENUM;
+    }
+    else {
+        param_protocol = "urn:oasis:names:tc:SAML:2.0:protocol"; // samlconstants::SAML20P_NS;
+    }
+    const auto_ptr_XMLCh protocol(param_protocol);
+
+    try {
+        scoped_ptr<ResolutionContext> ctx;
+
+        MetadataProvider* m = application.getMetadataProvider();
+        Locker mlock(m);
+
+        MetadataProviderCriteria mc(application, param_issuer, &IDPSSODescriptor::ELEMENT_QNAME, protocol.get());
+        pair<const EntityDescriptor*,const RoleDescriptor*> site = m->getEntityDescriptor(mc);
+        if (!site.first)
+            m_log.info("Unable to locate metadata for IdP (%s).", param_issuer);
+
+        // Build NameID(s).
+        scoped_ptr<saml1::NameIdentifier> v1name;
+        scoped_ptr<saml2::NameID> v2name(saml2::NameIDBuilder::buildNameID());
+        v2name->setName(nameid.get());
+        v2name->setFormat(format.get());
+        v2name->setNameQualifier(issuer.get());
+        v2name->setSPNameQualifier(application.getRelyingParty(site.first)->getXMLString("entityID").second);
+        if (!XMLString::equals(protocol.get(), samlconstants::SAML20P_NS)) {
+            v1name.reset(saml1::NameIdentifierBuilder::buildNameIdentifier());
+            v1name->setName(nameid.get());
+            v1name->setFormat(format.get());
+            v1name->setNameQualifier(issuer.get());
+        }
+
+        ctx.reset(resolveAttributes(application, &httpRequest, site.second, protocol.get(), v1name.get(), v2name.get()));
+
+        buildJSON(msg, ctx->getResolvedAttributes());
+    }
+    catch (std::exception& ex) {
+        m_log.error("error while processing request: %s", ex.what());
+        msg << "{}";
+        return make_pair(true, httpResponse.sendError(msg));
+    }
+    return make_pair(true, httpResponse.sendResponse(msg));
+#else
+    return make_pair(false, 0L);
+#endif
+}
+
+#ifndef SHIBSP_LITE
+ResolutionContext* AttributeResolverHandler::resolveAttributes(
+    const Application& application,
+    const GenericRequest* request,
+    const RoleDescriptor* issuer,
+    const XMLCh* protocol,
+    const saml1::NameIdentifier* v1nameid,
+    const saml2::NameID* nameid
+    ) const
+{
+    // First we do the extraction of any pushed information, including from metadata.
+    vector<Attribute*> resolvedAttributes;
+    AttributeExtractor* extractor = application.getAttributeExtractor();
+    if (extractor) {
+        Locker extlocker(extractor);
+        if (issuer) {
+            pair<bool,const char*> mprefix = application.getString("metadataAttributePrefix");
+            if (mprefix.first) {
+                m_log.debug("extracting metadata-derived attributes...");
+                try {
+                    // We pass nullptr for "issuer" because the IdP isn't the one asserting metadata-based attributes.
+                    extractor->extractAttributes(application, request, nullptr, *issuer, resolvedAttributes);
+                    for (indirect_iterator<vector<Attribute*>::iterator> a = make_indirect_iterator(resolvedAttributes.begin());
+                            a != make_indirect_iterator(resolvedAttributes.end()); ++a) {
+                        vector<string>& ids = a->getAliases();
+                        for (vector<string>::iterator id = ids.begin(); id != ids.end(); ++id)
+                            *id = mprefix.second + *id;
+                    }
+                }
+                catch (std::exception& ex) {
+                    m_log.error("caught exception extracting attributes: %s", ex.what());
+                }
+            }
+        }
+
+        m_log.debug("extracting attributes from NameID/NameIdentifier...");
+
+        if (v1nameid || nameid) {
+            try {
+                if (v1nameid)
+                    extractor->extractAttributes(application, request, issuer, *v1nameid, resolvedAttributes);
+                else
+                    extractor->extractAttributes(application, request, issuer, *nameid, resolvedAttributes);
+            }
+            catch (std::exception& ex) {
+                m_log.error("caught exception extracting attributes: %s", ex.what());
+            }
+        }
+
+        AttributeFilter* filter = application.getAttributeFilter();
+        if (filter && !resolvedAttributes.empty()) {
+            BasicFilteringContext fc(application, resolvedAttributes, issuer, nullptr, nullptr);
+            Locker filtlocker(filter);
+            try {
+                filter->filterAttributes(fc, resolvedAttributes);
+            }
+            catch (std::exception& ex) {
+                m_log.error("caught exception filtering attributes: %s", ex.what());
+                m_log.error("dumping extracted attributes due to filtering exception");
+                for_each(resolvedAttributes.begin(), resolvedAttributes.end(), xmltooling::cleanup<shibsp::Attribute>());
+                resolvedAttributes.clear();
+            }
+        }
+    }
+
+    try {
+        AttributeResolver* resolver = application.getAttributeResolver();
+        if (resolver) {
+            m_log.debug("resolving attributes...");
+
+            Locker locker(resolver);
+            auto_ptr<ResolutionContext> ctx(
+                resolver->createResolutionContext(
+                    application,
+                    request,
+                    issuer ? dynamic_cast<const saml2md::EntityDescriptor*>(issuer->getParent()) : nullptr,
+                    protocol,
+                    nameid,
+                    nullptr,
+                    nullptr,
+                    nullptr,
+                    &resolvedAttributes
+                    )
+                );
+            resolver->resolveAttributes(*ctx);
+            // Copy over any pushed attributes.
+            while (!resolvedAttributes.empty()) {
+                ctx->getResolvedAttributes().push_back(resolvedAttributes.back());
+                resolvedAttributes.pop_back();
+            }
+            return ctx.release();
+        }
+    }
+    catch (std::exception& ex) {
+        m_log.error("attribute resolution failed: %s", ex.what());
+    }
+
+    if (!resolvedAttributes.empty()) {
+        try {
+            return new DummyContext(resolvedAttributes);
+        }
+        catch (bad_alloc&) {
+            for_each(resolvedAttributes.begin(), resolvedAttributes.end(), xmltooling::cleanup<shibsp::Attribute>());
+        }
+    }
+    return nullptr;
+}
+
+ostream& AttributeResolverHandler::buildJSON(ostream& os, vector<shibsp::Attribute*>& attributes) const
+{
+    m_log.debug("building JSON from attributes..");
+
+    os << '{';
+
+    indirect_iterator<vector<Attribute*>::const_iterator> ahead = make_indirect_iterator(attributes.begin());
+    indirect_iterator<vector<Attribute*>::const_iterator> a = ahead;
+    for (; a != make_indirect_iterator(attributes.end()); ++a) {
+
+        if (a != ahead)
+            os << ',';
+
+        vector<string>::const_iterator shead = a->getAliases().begin();
+        for (vector<string>::const_iterator s = shead; s != a->getAliases().end(); ++s) {
+            if (s != shead)
+                os << ',';
+            os << endl << "    ";
+            json_safe(os, s->c_str());
+            os << " : ";
+
+            if (m_encoding.empty() || m_encoding == "JSON") {
+                os << '[' << endl;
+                vector<string>::const_iterator vhead = a->getSerializedValues().begin();
+                for (vector<string>::const_iterator v = vhead; v != a->getSerializedValues().end(); ++v) {
+                    if (v != vhead)
+                        os << ',';
+                    os << endl << "        ";
+                    json_safe(os, v->c_str());
+                }
+                os << endl << "    ]";
+            }
+            else if (m_encoding == "JSON/CGI") {
+                string attrValues;
+                vector<string>::const_iterator vhead = a->getSerializedValues().begin();
+                for (vector<string>::const_iterator v = vhead; v != a->getSerializedValues().end(); ++v) {
+                    if (v != vhead)
+                        attrValues += ';';
+                    string::size_type pos = v->find_first_of(';', string::size_type(0));
+                    if (pos != string::npos) {
+                        string value(*v);
+                        for (; pos != string::npos; pos = value.find_first_of(';', pos)) {
+                            value.insert(pos, "\\");
+                            pos += 2;
+                        }
+                        attrValues += value;
+                    }
+                    else {
+                        attrValues += *v;
+                    }
+                }
+                json_safe(os, attrValues.c_str());
+            }
+
+        }
+    }
+    if (a != ahead)
+        os << endl;
+
+    os << '}';
+
+    return os;
+}
+#endif
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 472088b..ee2dbec 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -8,6 +8,7 @@ noinst_HEADERS = \
 
 common_sources = \
 	plugins.cpp \
+    AttributeResolverHandler.cpp \
 	TimeAccessControl.cpp
 
 plugins_la_SOURCES = \
diff --git a/plugins/plugins.cpp b/plugins/plugins.cpp
index d23f127..b277f7f 100644
--- a/plugins/plugins.cpp
+++ b/plugins/plugins.cpp
@@ -42,6 +42,8 @@ using namespace std;
 
 namespace shibsp {
     PluginManager<AccessControl,string,const DOMElement*>::Factory TimeAccessControlFactory;
+    PluginManager<Handler,string,pair<const DOMElement*,const char*>>::Factory AttributeResolverHandlerFactory;
+    
 #ifndef SHIBSP_LITE
 # ifdef HAVE_GSSAPI_NAMINGEXTS
     PluginManager<AttributeExtractor,string,const DOMElement*>::Factory GSSAPIExtractorFactory;
@@ -57,6 +59,7 @@ extern "C" int PLUGINS_EXPORTS xmltooling_extension_init(void*)
 {
     SPConfig& conf = SPConfig::getConfig();
     conf.AccessControlManager.registerFactory("Time", TimeAccessControlFactory);
+    conf.HandlerManager.registerFactory("AttributeResolver", AttributeResolverHandlerFactory);
 #ifndef SHIBSP_LITE
 # ifdef HAVE_GSSAPI_NAMINGEXTS
     conf.AttributeExtractorManager.registerFactory("GSSAPI", GSSAPIExtractorFactory);

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-shibboleth/shibboleth-sp2.git



More information about the Pkg-shibboleth-devel mailing list