Migrated ShibTarget logic into ServiceProvider base.
authorcantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Thu, 18 Jan 2007 03:47:52 +0000 (03:47 +0000)
committercantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Thu, 18 Jan 2007 03:47:52 +0000 (03:47 +0000)
git-svn-id: https://svn.middleware.georgetown.edu/cpp-sp/trunk@2134 cb58f699-b61c-0410-a6fe-9272a202ed29

14 files changed:
apache/mod_apache.cpp
isapi_shib/isapi_shib.cpp
nsapi_shib/nsapi_shib.cpp
shib-target/Makefile.am
shib-target/shib-handlers.cpp
shib-target/shib-target.cpp [deleted file]
shib-target/shib-target.h
shib-target/shibtarget.vcproj
shibsp/Makefile.am
shibsp/ServiceProvider.cpp
shibsp/ServiceProvider.h
shibsp/shibsp.vcproj
shibsp/util/TemplateParameters.cpp [new file with mode: 0644]
shibsp/util/TemplateParameters.h [new file with mode: 0644]

index 3161beb..de20b46 100644 (file)
@@ -31,6 +31,7 @@
 # define _CRT_SECURE_NO_DEPRECATE 1
 #endif
 
+#include <shibsp/AbstractSPRequest.h>
 #include <shibsp/AccessControl.h>
 #include <shibsp/exceptions.h>
 #include <shibsp/RequestMapper.h>
@@ -73,7 +74,6 @@
 #endif
 
 using namespace shibsp;
-using namespace shibtarget;
 using namespace xmltooling;
 using namespace std;
 
@@ -82,7 +82,7 @@ extern "C" module MODULE_VAR_EXPORT mod_shib;
 namespace {
     char* g_szSHIBConfig = NULL;
     char* g_szSchemaDir = NULL;
-    ShibTargetConfig* g_Config = NULL;
+    shibtarget::ShibTargetConfig* g_Config = NULL;
     string g_unsetHeaderValue;
     static const char* g_UserDataKey = "_shib_check_user_";
 }
@@ -259,7 +259,7 @@ extern "C" const char* shib_ap_set_file_slot(cmd_parms* parms,
 /********************************************************************************/
 // Apache ShibTarget subclass(es) here.
 
-class ShibTargetApache : public ShibTarget
+class ShibTargetApache : public AbstractSPRequest
 {
   mutable string m_body;
   mutable bool m_gotBody;
@@ -438,12 +438,12 @@ extern "C" int shib_check_user(request_rec* r)
     ShibTargetApache sta(r);
 
     // Check user authentication and export information, then set the handler bypass
-    pair<bool,long> res = sta.doCheckAuthN(true);
+    pair<bool,long> res = sta.getServiceProvider().doAuthentication(sta,true);
     apr_pool_userdata_setn((const void*)42,g_UserDataKey,NULL,r->pool);
     if (res.first) return res.second;
 
     // user auth was okay -- export the assertions now
-    res = sta.doExportAssertions();
+    res = sta.getServiceProvider().doExport(sta);
     if (res.first) return res.second;
 
     // export happened successfully..  this user is ok.
@@ -488,7 +488,7 @@ extern "C" int shib_handler(request_rec* r)
   try {
     ShibTargetApache sta(r);
 
-    pair<bool,long> res = sta.doHandler();
+    pair<bool,long> res = sta.getServiceProvider().doHandler(sta);
     if (res.first) return res.second;
 
     ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, SH_AP_R(r), "doHandler() did not do anything.");
@@ -525,7 +525,7 @@ extern "C" int shib_auth_checker(request_rec* r)
   try {
     ShibTargetApache sta(r);
 
-    pair<bool,long> res = sta.doCheckAuthZ();
+    pair<bool,long> res = sta.getServiceProvider().doAuthorization(sta);
     if (res.first) return res.second;
 
     // We're all okay.
@@ -837,7 +837,7 @@ bool htAccessControl::authorized(const SPRequest& request, const Session* sessio
             }
         }
         else {
-            saml::Iterator<shibboleth::IAAP*> provs=dynamic_cast<const IApplication&>(request.getApplication()).getAAPProviders();
+            saml::Iterator<shibboleth::IAAP*> provs=dynamic_cast<const shibtarget::IApplication&>(request.getApplication()).getAAPProviders();
             shibboleth::AAP wrapper(provs,w);
             if (wrapper.fail()) {
                 request.log(SPRequest::SPWarn, string("htAccessControl plugin didn't recognize require rule: ") + w);
@@ -1044,7 +1044,7 @@ extern "C" void shib_child_init(apr_pool_t* p, server_rec* s)
     }
 
     try {
-        g_Config=&ShibTargetConfig::getConfig();
+        g_Config=&shibtarget::ShibTargetConfig::getConfig();
         SPConfig::getConfig().setFeatures(
             SPConfig::Caching |
             SPConfig::Listener |
index b9a5483..b1c1fad 100644 (file)
@@ -25,6 +25,7 @@
 #define _CRT_NONSTDC_NO_DEPRECATE 1
 #define _CRT_SECURE_NO_DEPRECATE 1
 
+#include <shibsp/AbstractSPRequest.h>
 #include <shibsp/SPConfig.h>
 #include <xmltooling/util/NDC.h>
 
@@ -41,7 +42,6 @@
 #include <httpext.h>
 
 using namespace shibsp;
-using namespace shibtarget;
 using namespace xmltooling;
 using namespace std;
 
@@ -83,7 +83,7 @@ namespace {
     };
     
     HINSTANCE g_hinstDLL;
-    ShibTargetConfig* g_Config = NULL;
+    shibtarget::ShibTargetConfig* g_Config = NULL;
     map<string,site_t> g_Sites;
     bool g_bNormalizeRequest = true;
 }
@@ -150,7 +150,7 @@ extern "C" BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer)
         LPCSTR config=getenv("SHIBCONFIG");
         if (!config)
             config=SHIB_CONFIG;
-        g_Config=&ShibTargetConfig::getConfig();
+        g_Config=&shibtarget::ShibTargetConfig::getConfig();
         SPConfig::getConfig().setFeatures(
             SPConfig::Listener |
             SPConfig::Caching |
@@ -328,7 +328,7 @@ void GetHeader(PHTTP_FILTER_PREPROC_HEADERS pn, PHTTP_FILTER_CONTEXT pfc,
 /****************************************************************************/
 // ISAPI Filter
 
-class ShibTargetIsapiF : public ShibTarget
+class ShibTargetIsapiF : public AbstractSPRequest
 {
   PHTTP_FILTER_CONTEXT m_pfc;
   PHTTP_FILTER_PREPROC_HEADERS m_pn;
@@ -550,14 +550,14 @@ extern "C" DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificat
         ShibTargetIsapiF stf(pfc, pn, map_i->second);
 
         // "false" because we don't override the Shib settings
-        pair<bool,long> res = stf.doCheckAuthN();
+        pair<bool,long> res = stf.getServiceProvider().doAuthentication(stf);
         if (res.first) return res.second;
 
         // "false" because we don't override the Shib settings
-        res = stf.doExportAssertions();
+        res = stf.getServiceProvider().doExport(stf);
         if (res.first) return res.second;
 
-        res = stf.doCheckAuthZ();
+        res = stf.getServiceProvider().doAuthorization(stf);
         if (res.first) return res.second;
 
         return SF_STATUS_REQ_NEXT_NOTIFICATION;
@@ -605,7 +605,7 @@ DWORD WriteClientError(LPEXTENSION_CONTROL_BLOCK lpECB, const char* msg)
 }
 
 
-class ShibTargetIsapiE : public ShibTarget
+class ShibTargetIsapiE : public AbstractSPRequest
 {
   LPEXTENSION_CONTROL_BLOCK m_lpECB;
   map<string,string> m_headers;
@@ -831,8 +831,6 @@ public:
 
 extern "C" DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB)
 {
-    string targeturl;
-    const IApplication* application=NULL;
     try {
         ostringstream threadid;
         threadid << "[" << getpid() << "] isapi_shib_extension" << '\0';
@@ -848,7 +846,7 @@ extern "C" DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB)
             return WriteClientError(lpECB, "Shibboleth Extension not configured for this web site.");
 
         ShibTargetIsapiE ste(lpECB, map_i->second);
-        pair<bool,long> res = ste.doHandler();
+        pair<bool,long> res = ste.getServiceProvider().doHandler(ste);
         if (res.first) return res.second;
         
         return WriteClientError(lpECB, "Shibboleth Extension failed to process request");
index 3af946c..a896a9c 100644 (file)
@@ -31,6 +31,7 @@
 # define _CRT_SECURE_NO_DEPRECATE 1
 #endif
 
+#include <shibsp/AbstractSPRequest.h>
 #include <shibsp/RequestMapper.h>
 #include <shibsp/SPConfig.h>
 #include <xmltooling/util/NDC.h>
@@ -60,7 +61,6 @@ extern "C"
 }
 
 using namespace shibsp;
-using namespace shibtarget;
 using namespace xmltooling;
 using namespace std;
 
@@ -69,7 +69,7 @@ using namespace std;
     if (IO_ERROR==net_write(sn->csd,str,strlen(str))) return REQ_EXIT
 
 namespace {
-    ShibTargetConfig* g_Config=NULL;
+    shibtarget::ShibTargetConfig* g_Config=NULL;
     string g_ServerName;
     string g_ServerScheme;
     string g_unsetHeaderValue;
@@ -125,7 +125,7 @@ extern "C" NSAPI_PUBLIC int nsapi_shib_init(pblock* pb, ::Session* sn, Request*
             config=getenv("SHIBCONFIG");
         if (!config)
             config=SHIB_CONFIG;
-        g_Config=&ShibTargetConfig::getConfig();
+        g_Config=&shibtarget::ShibTargetConfig::getConfig();
         SPConfig::getConfig().setFeatures(
             SPConfig::Listener |
             SPConfig::Caching |
@@ -173,7 +173,7 @@ extern "C" NSAPI_PUBLIC int nsapi_shib_init(pblock* pb, ::Session* sn, Request*
 /********************************************************************************/
 // NSAPI Shib Target Subclass
 
-class ShibTargetNSAPI : public ShibTarget
+class ShibTargetNSAPI : public AbstractSPRequest
 {
   string m_uri;
   mutable string m_body;
@@ -370,7 +370,7 @@ extern "C" NSAPI_PUBLIC int nsapi_shib(pblock* pb, ::Session* sn, Request* rq)
     ShibTargetNSAPI stn(pb, sn, rq);
 
     // Check user authentication
-    pair<bool,long> res = stn.doCheckAuthN();
+    pair<bool,long> res = stn.getServiceProvider().doAuthentication(stn);
     if (res.first) return (int)res.second;
 
     // user authN was okay -- export the assertions now
@@ -378,11 +378,11 @@ extern "C" NSAPI_PUBLIC int nsapi_shib(pblock* pb, ::Session* sn, Request* rq)
     // This seems to be required in order to eventually set
     // the auth-user var.
     pblock_nvinsert("auth-type","shibboleth",rq->vars);
-    res = stn.doExportAssertions();
+    res = stn.getServiceProvider().doExport(stn);
     if (res.first) return (int)res.second;
 
     // Check the Authorization
-    res = stn.doCheckAuthZ();
+    res = stn.getServiceProvider().doAuthorization(stn);
     if (res.first) return (int)res.second;
 
     // this user is ok.
@@ -411,7 +411,7 @@ extern "C" NSAPI_PUBLIC int shib_handler(pblock* pb, ::Session* sn, Request* rq)
   try {
     ShibTargetNSAPI stn(pb, sn, rq);
 
-    pair<bool,long> res = stn.doHandler();
+    pair<bool,long> res = stn.getServiceProvider().doHandler(stn);
     if (res.first) return (int)res.second;
 
     return WriteClientError(sn, rq, FUNC, "Shibboleth handler did not do anything.");
index 0206667..2ffa8d7 100644 (file)
@@ -17,8 +17,7 @@ libshib_target_la_SOURCES = \
        shib-ccache.cpp \
        shib-config.cpp \
        shib-handlers.cpp \
-       shib-ini.cpp \
-       shib-target.cpp
+       shib-ini.cpp
 
 # this is different from the project version
 # http://sources.redhat.com/autobook/autobook/autobook_91.html
index 822b703..b5f2105 100644 (file)
@@ -31,6 +31,7 @@
 #include <saml/util/CommonDomainCookie.h>
 #include <shibsp/AbstractHandler.h>
 #include <shibsp/SPConfig.h>
+#include <shibsp/SPRequest.h>
 
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
diff --git a/shib-target/shib-target.cpp b/shib-target/shib-target.cpp
deleted file mode 100644 (file)
index 10e86b4..0000000
+++ /dev/null
@@ -1,641 +0,0 @@
-/*
- *  Copyright 2001-2005 Internet2
- * 
- * 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
- *
- *     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.
- */
-
-/*
- * shib-target.cpp -- The ShibTarget class, a superclass for general
- *                   target code
- *
- * Created by: Derek Atkins <derek@ihtfp.com>
- *
- * $Id$
- */
-
-#include "internal.h"
-
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
-#include <fstream>
-
-#include <saml/SAMLConfig.h>
-#include <xercesc/util/Base64.hpp>
-#include <shibsp/AccessControl.h>
-#include <shibsp/RequestMapper.h>
-#include <xmltooling/util/NDC.h>
-#include <xmltooling/util/TemplateEngine.h>
-#include <xmltooling/util/XMLHelper.h>
-
-#ifndef HAVE_STRCASECMP
-# define strcasecmp stricmp
-#endif
-
-using namespace shibsp;
-using namespace shibtarget;
-using namespace shibboleth;
-using namespace saml;
-using namespace opensaml::saml2md;
-using namespace log4cpp;
-using namespace std;
-
-using xmltooling::TemplateEngine;
-using xmltooling::XMLToolingException;
-using xmltooling::XMLToolingConfig;
-using xmltooling::XMLHelper;
-
-namespace shibtarget {
-
-    class ExtTemplateParameters : public TemplateEngine::TemplateParameters
-    {
-        const PropertySet* m_props;
-    public:
-        ExtTemplateParameters() : m_props(NULL) {}
-        ~ExtTemplateParameters() {}
-
-        void setPropertySet(const PropertySet* props) {
-            m_props = props;
-
-            // Create a timestamp.
-            time_t now = time(NULL);
-#ifdef HAVE_CTIME_R
-            char timebuf[32];
-            m_map["now"] = ctime_r(&now,timebuf);
-#else
-            m_map["now"] = ctime(&now);
-#endif
-        }
-
-        const char* getParameter(const char* name) const {
-            const char* pch = TemplateParameters::getParameter(name);
-            if (pch || !m_props)
-                return pch;
-            pair<bool,const char*> p = m_props->getString(name);
-            return p.first ? p.second : NULL;
-        }
-    };
-
-    long _sendError(SPRequest* st, const char* page, ExtTemplateParameters& tp, const XMLToolingException* ex=NULL);
-
-    static const XMLCh SessionInitiator[] =     UNICODE_LITERAL_16(S,e,s,s,i,o,n,I,n,i,t,i,a,t,o,r);
-}
-
-
-/*************************************************************************
- * Shib Target implementation
- */
-
-
-
-// These functions implement the server-agnostic shibboleth engine
-// The web server modules implement a subclass and then call into 
-// these methods once they instantiate their request object.
-
-pair<bool,long> ShibTarget::doCheckAuthN(bool handler)
-{
-#ifdef _DEBUG
-    xmltooling::NDC ndc("doCheckAuthN");
-#endif
-
-    const char* procState = "Request Processing Error";
-    string targetURL = getRequestURL();
-    ExtTemplateParameters tp;
-
-    try {
-        RequestMapper::Settings settings = getRequestSettings();
-        const IApplication& app = dynamic_cast<const IApplication&>(getApplication());
-
-        // If not SSL, check to see if we should block or redirect it.
-        if (!strcmp("http",getScheme())) {
-            pair<bool,const char*> redirectToSSL = settings.first->getString("redirectToSSL");
-            if (redirectToSSL.first) {
-                if (!strcasecmp("GET",getMethod()) || !strcasecmp("HEAD",getMethod())) {
-                    // Compute the new target URL
-                    string redirectURL = string("https://") + getHostname();
-                    if (strcmp(redirectToSSL.second,"443")) {
-                        redirectURL = redirectURL + ':' + redirectToSSL.second;
-                    }
-                    redirectURL += getRequestURI();
-                    return make_pair(true, sendRedirect(redirectURL.c_str()));
-                }
-                else {
-                    tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?'));
-                    return make_pair(true,_sendError(this, "ssl", tp));
-                }
-            }
-        }
-        
-        const char* handlerURL=getHandlerURL(targetURL.c_str());
-        if (!handlerURL)
-            throw ConfigurationException("Cannot determine handler from resource URL, check configuration.");
-
-        // If the request URL contains the handler base URL for this application, either dispatch
-        // directly (mainly Apache 2.0) or just pass back control.
-        if (strstr(targetURL.c_str(),handlerURL)) {
-            if (handler)
-                return doHandler();
-            else
-                return make_pair(true, returnOK());
-        }
-
-        // Three settings dictate how to proceed.
-        pair<bool,const char*> authType = settings.first->getString("authType");
-        pair<bool,bool> requireSession = settings.first->getBool("requireSession");
-        pair<bool,const char*> requireSessionWith = settings.first->getString("requireSessionWith");
-
-        // If no session is required AND the AuthType (an Apache-derived concept) isn't shibboleth,
-        // then we ignore this request and consider it unprotected. Apache might lie to us if
-        // ShibBasicHijack is on, but that's up to it.
-        if ((!requireSession.first || !requireSession.second) && !requireSessionWith.first &&
-#ifdef HAVE_STRCASECMP
-                (!authType.first || strcasecmp(authType.second,"shibboleth")))
-#else
-                (!authType.first || _stricmp(authType.second,"shibboleth")))
-#endif
-            return make_pair(true,returnDecline());
-
-        // Fix for secadv 20050901
-        clearHeaders();
-
-        pair<string,const char*> shib_cookie = app.getCookieNameProps("_shibsession_");
-        const char* session_id = getCookie(shib_cookie.first.c_str());
-        if (!session_id || !*session_id) {
-            // No session.  Maybe that's acceptable?
-            if ((!requireSession.first || !requireSession.second) && !requireSessionWith.first)
-                return make_pair(true,returnOK());
-
-            // No cookie, but we require a session. Initiate a new session using the indicated method.
-            procState = "Session Initiator Error";
-            const Handler* initiator=NULL;
-            if (requireSessionWith.first) {
-                initiator=app.getSessionInitiatorById(requireSessionWith.second);
-                if (!initiator)
-                    throw ConfigurationException(
-                        "No session initiator found with id ($1), check requireSessionWith command.",
-                        xmltooling::params(1,requireSessionWith.second)
-                        );
-            }
-            else {
-                initiator=app.getDefaultSessionInitiator();
-                if (!initiator)
-                    throw ConfigurationException("No default session initiator found, check configuration.");
-            }
-
-            return initiator->run(*this,false);
-        }
-
-        procState = "Session Processing Error";
-        const Session* session=NULL;
-        try {
-            session=getSession();
-            // Make a localized exception throw if the session isn't valid.
-            if (!session)
-                throw RetryableProfileException("Session no longer valid.");
-        }
-        catch (exception& e) {
-            log(SPWarn, string("session processing failed: ") + e.what());
-
-            // If no session is required, bail now.
-            if ((!requireSession.first || !requireSession.second) && !requireSessionWith.first)
-                // Has to be OK because DECLINED will just cause Apache
-                // to fail when it can't locate anything to process the
-                // AuthType.  No session plus requireSession false means
-                // do not authenticate the user at this time.
-                return make_pair(true, returnOK());
-
-            // Try and cast down.
-            exception* base = &e;
-            RetryableProfileException* trycast=dynamic_cast<RetryableProfileException*>(base);
-            if (trycast) {
-                // Session is invalid but we can retry -- initiate a new session.
-                procState = "Session Initiator Error";
-                const Handler* initiator=NULL;
-                if (requireSessionWith.first) {
-                    initiator=app.getSessionInitiatorById(requireSessionWith.second);
-                    if (!initiator)
-                        throw ConfigurationException(
-                            "No session initiator found with id ($1), check requireSessionWith command.",
-                            xmltooling::params(1,requireSessionWith.second)
-                            );
-                }
-                else {
-                    initiator=app.getDefaultSessionInitiator();
-                    if (!initiator)
-                        throw ConfigurationException("No default session initiator found, check configuration.");
-                }
-                return initiator->run(*this,false);
-            }
-            throw;    // send it to the outer handler
-        }
-
-        // We're done.  Everything is okay.  Nothing to report.  Nothing to do..
-        // Let the caller decide how to proceed.
-        log(SPDebug, "doCheckAuthN succeeded");
-        return make_pair(false,0);
-    }
-    catch (XMLToolingException& e) {
-        tp.m_map["errorType"] = procState;
-        tp.m_map["errorText"] = e.what();
-        tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?'));
-        return make_pair(true,_sendError(this, "session", tp, &e));
-    }
-#ifndef _DEBUG
-    catch (...) {
-        tp.m_map["errorType"] = procState;
-        tp.m_map["errorText"] = "Caught an unknown exception.";
-        tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?'));
-        return make_pair(true,_sendError(this, "session", tp));
-    }
-#endif
-}
-
-pair<bool,long> ShibTarget::doHandler(void)
-{
-#ifdef _DEBUG
-    xmltooling::NDC ndc("doHandler");
-#endif
-
-    const IApplication* app=NULL;
-    ExtTemplateParameters tp;
-    const char* procState = "Shibboleth Handler Error";
-    string targetURL = getRequestURL();
-
-    try {
-        RequestMapper::Settings settings = getRequestSettings();
-        app = dynamic_cast<const IApplication*>(&getApplication());
-
-        const char* handlerURL=getHandlerURL(targetURL.c_str());
-        if (!handlerURL)
-            throw ConfigurationException("Cannot determine handler from resource URL, check configuration.");
-
-        // Make sure we only process handler requests.
-        if (!strstr(targetURL.c_str(),handlerURL))
-            return make_pair(true, returnDecline());
-
-        const PropertySet* sessionProps=app->getPropertySet("Sessions");
-        if (!sessionProps)
-            throw ConfigurationException("Unable to map request to application session settings, check configuration.");
-
-        // Process incoming request.
-        pair<bool,bool> handlerSSL=sessionProps->getBool("handlerSSL");
-      
-        // Make sure this is SSL, if it should be
-        if ((!handlerSSL.first || handlerSSL.second) && strcmp(getScheme(),"https"))
-            throw FatalProfileException("Blocked non-SSL access to Shibboleth handler.");
-
-        // We dispatch based on our path info. We know the request URL begins with or equals the handler URL,
-        // so the path info is the next character (or null).
-        const Handler* handler=app->getHandler(targetURL.c_str() + strlen(handlerURL));
-        if (!handler)
-            throw opensaml::BindingException("Shibboleth handler invoked at an unconfigured location.");
-
-        if (XMLHelper::isNodeNamed(handler->getElement(),samlconstants::SAML20MD_NS,AssertionConsumerService::LOCAL_NAME))
-            procState = "Session Creation Error";
-        else if (XMLString::equals(handler->getElement()->getLocalName(),SessionInitiator))
-            procState = "Session Initiator Error";
-        else if (XMLHelper::isNodeNamed(handler->getElement(),samlconstants::SAML20MD_NS,SingleLogoutService::LOCAL_NAME))
-            procState = "Session Termination Error";
-        else
-            procState = "Protocol Handler Error";
-        pair<bool,long> hret=handler->run(*this);
-
-        // Did the handler run successfully?
-        if (hret.first)
-            return hret;
-       
-        throw opensaml::BindingException("Configured Shibboleth handler failed to process the request.");
-    }
-    catch (MetadataException& e) {
-        tp.m_map["errorText"] = e.what();
-        // See if a metadata error page is installed.
-        const PropertySet* props=app->getPropertySet("Errors");
-        if (props) {
-            pair<bool,const char*> p=props->getString("metadata");
-            if (p.first) {
-                tp.m_map["errorType"] = procState;
-                tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?'));
-                return make_pair(true,_sendError(this, "metadata", tp));
-            }
-        }
-        throw;
-    }
-    catch (XMLToolingException& e) {
-        tp.m_map["errorType"] = procState;
-        tp.m_map["errorText"] = e.what();
-        tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?'));
-        return make_pair(true,_sendError(this, "session", tp, &e));
-    }
-#ifndef _DEBUG
-    catch (...) {
-        tp.m_map["errorType"] = procState;
-        tp.m_map["errorText"] = "Caught an unknown exception.";
-        tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?'));
-        return make_pair(true,_sendError(this, "session", tp));
-    }
-#endif
-}
-
-pair<bool,long> ShibTarget::doCheckAuthZ(void)
-{
-#ifdef _DEBUG
-    xmltooling::NDC ndc("doCheckAuthZ");
-#endif
-
-    const IApplication* app=NULL;
-    ExtTemplateParameters tp;
-    const char* procState = "Authorization Processing Error";
-    string targetURL = getRequestURL();
-
-    try {
-        RequestMapper::Settings settings = getRequestSettings();
-        app = dynamic_cast<const IApplication*>(&getApplication());
-
-        // Three settings dictate how to proceed.
-        pair<bool,const char*> authType = settings.first->getString("authType");
-        pair<bool,bool> requireSession = settings.first->getBool("requireSession");
-        pair<bool,const char*> requireSessionWith = settings.first->getString("requireSessionWith");
-
-        // If no session is required AND the AuthType (an Apache-derived concept) isn't shibboleth,
-        // then we ignore this request and consider it unprotected. Apache might lie to us if
-        // ShibBasicHijack is on, but that's up to it.
-        if ((!requireSession.first || !requireSession.second) && !requireSessionWith.first &&
-#ifdef HAVE_STRCASECMP
-                (!authType.first || strcasecmp(authType.second,"shibboleth")))
-#else
-                (!authType.first || _stricmp(authType.second,"shibboleth")))
-#endif
-            return make_pair(true,returnDecline());
-
-        // Do we have an access control plugin?
-        if (settings.second) {
-            const Session* session =NULL;
-               pair<string,const char*> shib_cookie=app->getCookieNameProps("_shibsession_");
-            const char *session_id = getCookie(shib_cookie.first.c_str());
-            try {
-                       if (session_id && *session_id) {
-                    session = getSession();
-                       }
-            }
-            catch (exception&) {
-               log(SPWarn, "doCheckAuthZ: unable to obtain session information to pass to access control provider");
-            }
-       
-            xmltooling::Locker acllock(settings.second);
-            if (settings.second->authorized(*this,session)) {
-                // Let the caller decide how to proceed.
-                log(SPDebug, "doCheckAuthZ: access control provider granted access");
-                return make_pair(false,0);
-            }
-            else {
-                log(SPWarn, "doCheckAuthZ: access control provider denied access");
-                tp.m_map["requestURL"] = targetURL;
-                return make_pair(true,_sendError(this, "access", tp));
-            }
-            return make_pair(false,0);
-        }
-        else
-            return make_pair(true,returnDecline());
-    }
-    catch (exception& e) {
-        tp.m_map["errorType"] = procState;
-        tp.m_map["errorText"] = e.what();
-        tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?'));
-        return make_pair(true,_sendError(this, "access", tp));
-    }
-#ifndef _DEBUG
-    catch (...) {
-        tp.m_map["errorType"] = procState;
-        tp.m_map["errorText"] = "Caught an unknown exception.";
-        tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?'));
-        return make_pair(true,_sendError(this, "access", tp));
-    }
-#endif
-}
-
-pair<bool,long> ShibTarget::doExportAssertions(bool requireSession)
-{
-#ifdef _DEBUG
-    xmltooling::NDC ndc("doExportAssertions");
-#endif
-
-    const IApplication* app=NULL;
-    ExtTemplateParameters tp;
-    const char* procState = "Attribute Processing Error";
-    string targetURL = getRequestURL();
-
-    try {
-        RequestMapper::Settings settings = getRequestSettings();
-        app = dynamic_cast<const IApplication*>(&getApplication());
-
-        const Session* session=NULL;
-        pair<string,const char*> shib_cookie=app->getCookieNameProps("_shibsession_");
-        const char *session_id = getCookie(shib_cookie.first.c_str());
-        try {
-               if (session_id && *session_id) {
-                session = getSession();
-               }
-        }
-        catch (exception&) {
-               log(SPWarn, "unable to obtain session information to export into request headers");
-               // If we have to have a session, then this is a fatal error.
-               if (requireSession)
-                       throw;
-        }
-
-               // Still no data?
-        if (!session) {
-               if (requireSession)
-                       throw RetryableProfileException("Unable to obtain session information for request.");
-               else
-                       return make_pair(false,0);      // just bail silently
-        }
-        
-        /*
-        TODO: port to new cache API
-        // Extract data from session.
-        pair<const char*,const SAMLSubject*> sub=m_cacheEntry->getSubject(false,true);
-        pair<const char*,const SAMLResponse*> unfiltered=m_cacheEntry->getTokens(true,false);
-        pair<const char*,const SAMLResponse*> filtered=m_cacheEntry->getTokens(false,true);
-
-        // Maybe export the tokens.
-        pair<bool,bool> exp=m_settings.first->getBool("exportAssertion");
-        if (exp.first && exp.second && unfiltered.first && *unfiltered.first) {
-            unsigned int outlen;
-            XMLByte* serialized =
-                Base64::encode(reinterpret_cast<XMLByte*>((char*)unfiltered.first), XMLString::stringLen(unfiltered.first), &outlen);
-            XMLByte *pos, *pos2;
-            for (pos=serialized, pos2=serialized; *pos2; pos2++)
-                if (isgraph(*pos2))
-                    *pos++=*pos2;
-            *pos=0;
-            setHeader("Shib-Attributes", reinterpret_cast<char*>(serialized));
-            XMLString::release(&serialized);
-        }
-
-        // Export the SAML AuthnMethod and the origin site name, and possibly the NameIdentifier.
-        setHeader("Shib-Origin-Site", m_cacheEntry->getProviderId());
-        setHeader("Shib-Identity-Provider", m_cacheEntry->getProviderId());
-        setHeader("Shib-Authentication-Method", m_cacheEntry->getAuthnContext());
-        
-        // Get the AAP providers, which contain the attribute policy info.
-        Iterator<IAAP*> provs=m_app->getAAPProviders();
-
-        // Export NameID?
-        while (provs.hasNext()) {
-            IAAP* aap=provs.next();
-            xmltooling::Locker locker(aap);
-            const XMLCh* format = sub.second->getNameIdentifier()->getFormat();
-            const IAttributeRule* rule=aap->lookup(format ? format : SAMLNameIdentifier::UNSPECIFIED);
-            if (rule && rule->getHeader()) {
-                auto_ptr_char form(format ? format : SAMLNameIdentifier::UNSPECIFIED);
-                auto_ptr_char nameid(sub.second->getNameIdentifier()->getName());
-                setHeader("Shib-NameIdentifier-Format", form.get());
-                if (!strcmp(rule->getHeader(),"REMOTE_USER"))
-                    setRemoteUser(nameid.get());
-                else
-                    setHeader(rule->getHeader(), nameid.get());
-            }
-        }
-        
-        setHeader("Shib-Application-ID", m_app->getId());
-    
-        // Export the attributes.
-        Iterator<SAMLAssertion*> a_iter(filtered.second ? filtered.second->getAssertions() : EMPTY(SAMLAssertion*));
-        while (a_iter.hasNext()) {
-            SAMLAssertion* assert=a_iter.next();
-            Iterator<SAMLStatement*> statements=assert->getStatements();
-            while (statements.hasNext()) {
-                SAMLAttributeStatement* astate=dynamic_cast<SAMLAttributeStatement*>(statements.next());
-                if (!astate)
-                    continue;
-                Iterator<SAMLAttribute*> attrs=astate->getAttributes();
-                while (attrs.hasNext()) {
-                    SAMLAttribute* attr=attrs.next();
-            
-                    // Are we supposed to export it?
-                    provs.reset();
-                    while (provs.hasNext()) {
-                        IAAP* aap=provs.next();
-                        xmltooling::Locker locker(aap);
-                        const IAttributeRule* rule=aap->lookup(attr->getName(),attr->getNamespace());
-                        if (!rule || !rule->getHeader())
-                            continue;
-                    
-                        Iterator<string> vals=attr->getSingleByteValues();
-                        if (!strcmp(rule->getHeader(),"REMOTE_USER") && vals.hasNext())
-                            setRemoteUser(vals.next().c_str());
-                        else {
-                            int it=0;
-                            string header = getSecureHeader(rule->getHeader());
-                            if (!header.empty())
-                                it++;
-                            for (; vals.hasNext(); it++) {
-                                string value = vals.next();
-                                for (string::size_type pos = value.find_first_of(";", string::size_type(0));
-                                        pos != string::npos;
-                                        pos = value.find_first_of(";", pos)) {
-                                    value.insert(pos, "\\");
-                                    pos += 2;
-                                }
-                                if (it)
-                                    header += ";";
-                                header += value;
-                            }
-                            setHeader(rule->getHeader(), header.c_str());
-                        }
-                    }
-                }
-            }
-        }
-        */
-    
-        return make_pair(false,0);
-    }
-    catch (XMLToolingException& e) {
-        tp.m_map["errorType"] = procState;
-        tp.m_map["errorText"] = e.what();
-        tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?'));
-        return make_pair(true,_sendError(this, "rm", tp, &e));
-    }
-#ifndef _DEBUG
-    catch (...) {
-        tp.m_map["errorType"] = procState;
-        tp.m_map["errorText"] = "Caught an unknown exception.";
-        tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?'));
-        return make_pair(true,_sendError(this, "rm", tp));
-    }
-#endif
-}
-
-/*************************************************************************
- * Shib Target Private implementation
- */
-
-long shibtarget::_sendError(
-    SPRequest* st, const char* page, ExtTemplateParameters& tp, const XMLToolingException* ex
-    )
-{
-    st->setContentType("text/html");
-    st->setResponseHeader("Expires","01-Jan-1997 12:00:00 GMT");
-    st->setResponseHeader("Cache-Control","private,no-store,no-cache");
-
-    TemplateEngine* engine = XMLToolingConfig::getConfig().getTemplateEngine();
-    const PropertySet* props=st->getApplication().getPropertySet("Errors");
-    if (props) {
-        pair<bool,const char*> p=props->getString(page);
-        if (p.first) {
-            ifstream infile(p.second);
-            if (infile) {
-                tp.setPropertySet(props);
-                stringstream str;
-                engine->run(infile, str, tp, ex);
-                return st->sendResponse(str);
-            }
-        }
-        else if (!strcmp(page,"access")) {
-            istringstream msg("Access Denied");
-            return static_cast<opensaml::GenericResponse*>(st)->sendResponse(msg, opensaml::HTTPResponse::SAML_HTTP_STATUS_FORBIDDEN);
-        }
-    }
-
-    string errstr = string("sendError could not process error template (") + page + ")";
-    st->log(SPRequest::SPError, errstr);
-    istringstream msg("Internal Server Error. Please contact the site administrator.");
-    return st->sendError(msg);
-}
-
-void ShibTarget::clearHeaders()
-{
-    // Clear invariant stuff.
-    clearHeader("Shib-Origin-Site");
-    clearHeader("Shib-Identity-Provider");
-    clearHeader("Shib-Authentication-Method");
-    clearHeader("Shib-NameIdentifier-Format");
-    clearHeader("Shib-Attributes");
-    clearHeader("Shib-Application-ID");
-
-    // Clear out the list of mapped attributes
-    Iterator<IAAP*> provs=dynamic_cast<const IApplication&>(getApplication()).getAAPProviders();
-    while (provs.hasNext()) {
-        IAAP* aap=provs.next();
-        xmltooling::Locker locker(aap);
-        Iterator<const IAttributeRule*> rules=aap->getAttributeRules();
-        while (rules.hasNext()) {
-            const char* header=rules.next()->getHeader();
-            if (header)
-                clearHeader(header);
-        }
-    }
-}
index 782c31e..15e6913 100644 (file)
@@ -26,7 +26,6 @@
 #define SHIB_TARGET_H
 
 // New headers
-#include <shibsp/AbstractSPRequest.h>
 #include <shibsp/Application.h>
 #include <shibsp/Handler.h>
 #include <shibsp/RequestMapper.h>
@@ -234,45 +233,6 @@ namespace shibtarget {
         static ShibTargetConfig& getConfig();
     };
 
-    class ShibTargetPriv;
-    class SHIBTARGET_EXPORTS ShibTarget : public shibsp::AbstractSPRequest {
-    public:
-        virtual ~ShibTarget() {}
-
-        //
-        // Note:  Subclasses need not implement anything below this line
-        //
-
-        // These functions implement the server-agnostic shibboleth engine
-        // The web server modules implement a subclass and then call into 
-        // these methods once they instantiate their request object.
-        // 
-        // Return value:
-        //   these APIs will always return the result of sendPage(), sendRedirect(),
-        //   returnDecline(), or returnOK() in the void* portion of the return code.
-        //   Exactly what those values are is module- (subclass-) implementation
-        //   specific.  The 'bool' part of the return value declares whether the
-        //   void* is valid or not.  If the bool is true then the void* is valid.
-        //   If the bool is false then the API did not call any callback, the void*
-        //   is not valid, and the caller should continue processing (the API Call
-        //   finished successfully).
-        //
-        //   The handleProfile argument declares whether doCheckAuthN() should
-        //   automatically call doHandlePOST() when it encounters a request for
-        //   the ShireURL;  if false it will call returnOK() instead.
-        //
-        std::pair<bool,long> doCheckAuthN(bool handler = false);
-        std::pair<bool,long> doHandler();
-        std::pair<bool,long> doCheckAuthZ();
-        std::pair<bool,long> doExportAssertions(bool requireSession = true);
-
-    protected:
-        ShibTarget() {}
-
-    private:
-        void clearHeaders();
-    };
-
 }
 
 #endif /* SHIB_TARGET_H */
index d5cd8d6..49d8d83 100644 (file)
                        >
                </File>
                <File
-                       RelativePath="shib-target.cpp"
-                       >
-               </File>
-               <File
                        RelativePath="shib-target.h"
                        >
                </File>
index 8924527..b30255b 100644 (file)
@@ -44,7 +44,8 @@ secinclude_HEADERS = \
 utilinclude_HEADERS = \
        util/DOMPropertySet.h \
        util/PropertySet.h \
-       util/SPConstants.h
+       util/SPConstants.h \
+       util/TemplateParameters.h
 
 noinst_HEADERS = \
        internal.h \
@@ -68,7 +69,8 @@ libshibsp_la_SOURCES = \
        remoting/impl/UnixListener.cpp \
        security/PKIXTrustEngine.cpp \
        util/DOMPropertySet.cpp \
-       util/SPConstants.cpp 
+       util/SPConstants.cpp \
+       util/TemplateParameters.cpp
 
 # this is different from the project version
 # http://sources.redhat.com/autobook/autobook/autobook_91.html
index 0744e35..7e41392 100644 (file)
  */
 
 #include "internal.h"
+#include "exceptions.h"
+#include "AccessControl.h"
+#include "Application.h"
+#include "Handler.h"
 #include "ServiceProvider.h"
+#include "SessionCache.h"
+#include "SPRequest.h"
+#include "util/TemplateParameters.h"
 
-#include <xercesc/dom/DOM.hpp>
+#include <fstream>
+#include <sstream>
+#include <saml/saml2/metadata/Metadata.h>
+#include <saml/util/SAMLConstants.h>
+#include <xmltooling/XMLToolingConfig.h>
+#include <xmltooling/util/NDC.h>\r
+#include <xmltooling/util/XMLHelper.h>\r
 
 using namespace shibsp;
+using namespace opensaml::saml2md;
+using namespace opensaml;
 using namespace xmltooling;
-using namespace xercesc;
 using namespace std;
 
 namespace shibsp {
     //SHIBSP_DLLLOCAL PluginManager<ServiceProvider,const DOMElement*>::Factory XMLServiceProviderFactory;
+
+    long SHIBSP_DLLLOCAL sendError(
+        SPRequest& request, const Application* app, const char* page, TemplateParameters& tp, const XMLToolingException* ex=NULL
+        )
+    {
+        request.setContentType("text/html");
+        request.setResponseHeader("Expires","01-Jan-1997 12:00:00 GMT");
+        request.setResponseHeader("Cache-Control","private,no-store,no-cache");
+    
+        const PropertySet* props=app ? app->getPropertySet("Errors") : NULL;
+        if (props) {
+            pair<bool,const char*> p=props->getString(page);
+            if (p.first) {
+                ifstream infile(p.second);
+                if (infile) {
+                    tp.setPropertySet(props);
+                    stringstream str;
+                    XMLToolingConfig::getConfig().getTemplateEngine()->run(infile, str, tp, ex);
+                    return request.sendResponse(str);
+                }
+            }
+            else if (!strcmp(page,"access")) {
+                istringstream msg("Access Denied");
+                return static_cast<opensaml::GenericResponse&>(request).sendResponse(msg, HTTPResponse::SAML_HTTP_STATUS_FORBIDDEN);
+            }
+        }
+    
+        string errstr = string("sendError could not process error template (") + page + ")";
+        request.log(SPRequest::SPError, errstr);
+        istringstream msg("Internal Server Error. Please contact the site administrator.");
+        return request.sendError(msg);
+    }
+    
+    void SHIBSP_DLLLOCAL clearHeaders(SPRequest& request) {
+        // Clear invariant stuff.
+        request.clearHeader("Shib-Origin-Site");
+        request.clearHeader("Shib-Identity-Provider");
+        request.clearHeader("Shib-Authentication-Method");
+        request.clearHeader("Shib-NameIdentifier-Format");
+        request.clearHeader("Shib-Attributes");
+        request.clearHeader("Shib-Application-ID");
+    
+        // Clear out the list of mapped attributes
+        /* TODO: port
+        Iterator<IAAP*> provs=dynamic_cast<const IApplication&>(getApplication()).getAAPProviders();
+        while (provs.hasNext()) {
+            IAAP* aap=provs.next();
+            xmltooling::Locker locker(aap);
+            Iterator<const IAttributeRule*> rules=aap->getAttributeRules();
+            while (rules.hasNext()) {
+                const char* header=rules.next()->getHeader();
+                if (header)
+                    request.clearHeader(header);
+            }
+        }
+        */
+    }
+
+    static const XMLCh SessionInitiator[] =     UNICODE_LITERAL_16(S,e,s,s,i,o,n,I,n,i,t,i,a,t,o,r);\r
 };
 
 void SHIBSP_API shibsp::registerServiceProviders()
@@ -41,20 +114,516 @@ void SHIBSP_API shibsp::registerServiceProviders()
 
 pair<bool,long> ServiceProvider::doAuthentication(SPRequest& request, bool handler) const
 {
-    return make_pair(true,0);
+#ifdef _DEBUG\r
+    xmltooling::NDC ndc("doAuthentication");\r
+#endif\r
+\r
+    const Application* app=NULL;\r
+    const char* procState = "Request Processing Error";\r
+    string targetURL = request.getRequestURL();\r
+\r
+    try {\r
+        RequestMapper::Settings settings = request.getRequestSettings();\r
+        app = &(request.getApplication());\r
+\r
+        // If not SSL, check to see if we should block or redirect it.\r
+        if (!request.isSecure()) {\r
+            pair<bool,const char*> redirectToSSL = settings.first->getString("redirectToSSL");\r
+            if (redirectToSSL.first) {\r
+#ifdef HAVE_STRCASECMP\r
+                if (!strcasecmp("GET",request.getMethod()) || !strcasecmp("HEAD",request.getMethod())) {\r
+#else\r
+                if (!stricmp("GET",request.getMethod()) || !stricmp("HEAD",request.getMethod())) {\r
+#endif\r
+                    // Compute the new target URL\r
+                    string redirectURL = string("https://") + request.getHostname();\r
+                    if (strcmp(redirectToSSL.second,"443")) {\r
+                        redirectURL = redirectURL + ':' + redirectToSSL.second;\r
+                    }\r
+                    redirectURL += request.getRequestURI();\r
+                    return make_pair(true, request.sendRedirect(redirectURL.c_str()));\r
+                }\r
+                else {\r
+                    TemplateParameters tp;\r
+                    tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?'));\r
+                    return make_pair(true,sendError(request, app, "ssl", tp));\r
+                }\r
+            }\r
+        }\r
+        \r
+        const char* handlerURL=request.getHandlerURL(targetURL.c_str());\r
+        if (!handlerURL)\r
+            throw ConfigurationException("Cannot determine handler from resource URL, check configuration.");\r
+\r
+        // If the request URL contains the handler base URL for this application, either dispatch\r
+        // directly (mainly Apache 2.0) or just pass back control.\r
+        if (strstr(targetURL.c_str(),handlerURL)) {\r
+            if (handler)\r
+                return doHandler(request);\r
+            else\r
+                return make_pair(true, request.returnOK());\r
+        }\r
+\r
+        // Three settings dictate how to proceed.\r
+        pair<bool,const char*> authType = settings.first->getString("authType");\r
+        pair<bool,bool> requireSession = settings.first->getBool("requireSession");\r
+        pair<bool,const char*> requireSessionWith = settings.first->getString("requireSessionWith");\r
+\r
+        // If no session is required AND the AuthType (an Apache-derived concept) isn't shibboleth,\r
+        // then we ignore this request and consider it unprotected. Apache might lie to us if\r
+        // ShibBasicHijack is on, but that's up to it.\r
+        if ((!requireSession.first || !requireSession.second) && !requireSessionWith.first &&\r
+#ifdef HAVE_STRCASECMP\r
+                (!authType.first || strcasecmp(authType.second,"shibboleth")))\r
+#else\r
+                (!authType.first || _stricmp(authType.second,"shibboleth")))\r
+#endif\r
+            return make_pair(true,request.returnDecline());\r
+\r
+        // Fix for secadv 20050901\r
+        clearHeaders(request);\r
+\r
+        pair<string,const char*> shib_cookie = app->getCookieNameProps("_shibsession_");\r
+        const char* session_id = request.getCookie(shib_cookie.first.c_str());\r
+        if (!session_id || !*session_id) {\r
+            // No session.  Maybe that's acceptable?\r
+            if ((!requireSession.first || !requireSession.second) && !requireSessionWith.first)\r
+                return make_pair(true,request.returnOK());\r
+\r
+            // No cookie, but we require a session. Initiate a new session using the indicated method.\r
+            procState = "Session Initiator Error";\r
+            const Handler* initiator=NULL;\r
+            if (requireSessionWith.first) {\r
+                initiator=app->getSessionInitiatorById(requireSessionWith.second);\r
+                if (!initiator)\r
+                    throw ConfigurationException(\r
+                        "No session initiator found with id ($1), check requireSessionWith command.",\r
+                        params(1,requireSessionWith.second)\r
+                        );\r
+            }\r
+            else {\r
+                initiator=app->getDefaultSessionInitiator();\r
+                if (!initiator)\r
+                    throw ConfigurationException("No default session initiator found, check configuration.");\r
+            }\r
+\r
+            return initiator->run(request,false);\r
+        }\r
+\r
+        procState = "Session Processing Error";\r
+        const Session* session=NULL;\r
+        try {\r
+            session=request.getSession();\r
+            // Make a localized exception throw if the session isn't valid.\r
+            if (!session)\r
+                throw RetryableProfileException("Session no longer valid.");\r
+        }\r
+        catch (exception& e) {\r
+            request.log(SPRequest::SPWarn, string("session processing failed: ") + e.what());\r
+\r
+            // If no session is required, bail now.\r
+            if ((!requireSession.first || !requireSession.second) && !requireSessionWith.first)\r
+                // Has to be OK because DECLINED will just cause Apache\r
+                // to fail when it can't locate anything to process the\r
+                // AuthType.  No session plus requireSession false means\r
+                // do not authenticate the user at this time.\r
+                return make_pair(true, request.returnOK());\r
+\r
+            // Try and cast down.\r
+            exception* base = &e;\r
+            RetryableProfileException* trycast=dynamic_cast<RetryableProfileException*>(base);\r
+            if (trycast) {\r
+                // Session is invalid but we can retry -- initiate a new session.\r
+                procState = "Session Initiator Error";\r
+                const Handler* initiator=NULL;\r
+                if (requireSessionWith.first) {\r
+                    initiator=app->getSessionInitiatorById(requireSessionWith.second);\r
+                    if (!initiator)\r
+                        throw ConfigurationException(\r
+                            "No session initiator found with id ($1), check requireSessionWith command.",\r
+                            params(1,requireSessionWith.second)\r
+                            );\r
+                }\r
+                else {\r
+                    initiator=app->getDefaultSessionInitiator();\r
+                    if (!initiator)\r
+                        throw ConfigurationException("No default session initiator found, check configuration.");\r
+                }\r
+                return initiator->run(request,false);\r
+            }\r
+            throw;    // send it to the outer handler\r
+        }\r
+\r
+        // We're done.  Everything is okay.  Nothing to report.  Nothing to do..\r
+        // Let the caller decide how to proceed.\r
+        request.log(SPRequest::SPDebug, "doAuthentication succeeded");\r
+        return make_pair(false,0);\r
+    }\r
+    catch (XMLToolingException& e) {\r
+        TemplateParameters tp;\r
+        tp.m_map["errorType"] = procState;\r
+        tp.m_map["errorText"] = e.what();\r
+        tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?'));\r
+        return make_pair(true,sendError(request, app, "session", tp, &e));\r
+    }\r
+    catch (exception& e) {\r
+        TemplateParameters tp;\r
+        tp.m_map["errorType"] = procState;\r
+        tp.m_map["errorText"] = e.what();\r
+        tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?'));\r
+        return make_pair(true,sendError(request, app, "session", tp));\r
+    }\r
+#ifndef _DEBUG\r
+    catch (...) {\r
+        TemplateParameters tp;\r
+        tp.m_map["errorType"] = procState;\r
+        tp.m_map["errorText"] = "Caught an unknown exception.";\r
+        tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?'));\r
+        return make_pair(true,sendError(request, app, "session", tp));\r
+    }\r
+#endif\r
 }
 
 pair<bool,long> ServiceProvider::doAuthorization(SPRequest& request) const
 {
-    return make_pair(true,0);
+#ifdef _DEBUG\r
+    xmltooling::NDC ndc("doAuthorization");\r
+#endif\r
+\r
+    const Application* app=NULL;\r
+    const char* procState = "Authorization Processing Error";\r
+    string targetURL = request.getRequestURL();\r
+\r
+    try {\r
+        RequestMapper::Settings settings = request.getRequestSettings();\r
+        app = &(request.getApplication());\r
+\r
+        // Three settings dictate how to proceed.\r
+        pair<bool,const char*> authType = settings.first->getString("authType");\r
+        pair<bool,bool> requireSession = settings.first->getBool("requireSession");\r
+        pair<bool,const char*> requireSessionWith = settings.first->getString("requireSessionWith");\r
+\r
+        // If no session is required AND the AuthType (an Apache-derived concept) isn't shibboleth,\r
+        // then we ignore this request and consider it unprotected. Apache might lie to us if\r
+        // ShibBasicHijack is on, but that's up to it.\r
+        if ((!requireSession.first || !requireSession.second) && !requireSessionWith.first &&\r
+#ifdef HAVE_STRCASECMP\r
+                (!authType.first || strcasecmp(authType.second,"shibboleth")))\r
+#else\r
+                (!authType.first || _stricmp(authType.second,"shibboleth")))\r
+#endif\r
+            return make_pair(true,request.returnDecline());\r
+\r
+        // Do we have an access control plugin?\r
+        if (settings.second) {\r
+            const Session* session =NULL;\r
+               pair<string,const char*> shib_cookie=app->getCookieNameProps("_shibsession_");\r
+            const char *session_id = request.getCookie(shib_cookie.first.c_str());\r
+            try {\r
+                       if (session_id && *session_id) {\r
+                    session = request.getSession();\r
+                       }\r
+            }\r
+            catch (exception&) {\r
+                request.log(SPRequest::SPWarn, "unable to obtain session information to pass to access control provider");\r
+            }\r
+       \r
+            Locker acllock(settings.second);\r
+            if (settings.second->authorized(request,session)) {\r
+                // Let the caller decide how to proceed.\r
+                request.log(SPRequest::SPDebug, "access control provider granted access");\r
+                return make_pair(false,0);\r
+            }\r
+            else {\r
+                request.log(SPRequest::SPWarn, "access control provider denied access");\r
+                TemplateParameters tp;\r
+                tp.m_map["requestURL"] = targetURL;\r
+                return make_pair(true,sendError(request, app, "access", tp));\r
+            }\r
+            return make_pair(false,0);\r
+        }\r
+        else\r
+            return make_pair(true,request.returnDecline());\r
+    }\r
+    catch (XMLToolingException& e) {
+        TemplateParameters tp;
+        tp.m_map["errorType"] = procState;
+        tp.m_map["errorText"] = e.what();
+        tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?'));
+        return make_pair(true,sendError(request, app, "session", tp, &e));
+    }
+    catch (exception& e) {\r
+        TemplateParameters tp;\r
+        tp.m_map["errorType"] = procState;\r
+        tp.m_map["errorText"] = e.what();\r
+        tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?'));\r
+        return make_pair(true,sendError(request, app, "access", tp));\r
+    }\r
+#ifndef _DEBUG\r
+    catch (...) {\r
+        TemplateParameters tp;\r
+        tp.m_map["errorType"] = procState;\r
+        tp.m_map["errorText"] = "Caught an unknown exception.";\r
+        tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?'));\r
+        return make_pair(true,sendError(request, app, "access", tp));\r
+    }\r
+#endif\r
 }
 
 pair<bool,long> ServiceProvider::doExport(SPRequest& request, bool requireSession) const
 {
-    return make_pair(true,0);
+#ifdef _DEBUG\r
+    xmltooling::NDC ndc("doExport");\r
+#endif\r
+\r
+    const Application* app=NULL;\r
+    const char* procState = "Attribute Processing Error";\r
+    string targetURL = request.getRequestURL();\r
+\r
+    try {\r
+        RequestMapper::Settings settings = request.getRequestSettings();
+        app = &(request.getApplication());
+\r
+        const Session* session=NULL;\r
+        pair<string,const char*> shib_cookie=app->getCookieNameProps("_shibsession_");\r
+        const char *session_id = request.getCookie(shib_cookie.first.c_str());\r
+        try {\r
+               if (session_id && *session_id) {\r
+                session = request.getSession();\r
+               }\r
+        }\r
+        catch (exception&) {\r
+            request.log(SPRequest::SPWarn, "unable to obtain session information to export into request headers");\r
+               // If we have to have a session, then this is a fatal error.\r
+               if (requireSession)\r
+                       throw;\r
+        }\r
+\r
+               // Still no data?\r
+        if (!session) {\r
+               if (requireSession)\r
+                       throw RetryableProfileException("Unable to obtain session information for request.");\r
+               else\r
+                       return make_pair(false,0);      // just bail silently\r
+        }\r
+        \r
+        /*\r
+        TODO: port to new cache API\r
+        // Extract data from session.\r
+        pair<const char*,const SAMLSubject*> sub=m_cacheEntry->getSubject(false,true);\r
+        pair<const char*,const SAMLResponse*> unfiltered=m_cacheEntry->getTokens(true,false);\r
+        pair<const char*,const SAMLResponse*> filtered=m_cacheEntry->getTokens(false,true);\r
+\r
+        // Maybe export the tokens.\r
+        pair<bool,bool> exp=m_settings.first->getBool("exportAssertion");\r
+        if (exp.first && exp.second && unfiltered.first && *unfiltered.first) {\r
+            unsigned int outlen;\r
+            XMLByte* serialized =\r
+                Base64::encode(reinterpret_cast<XMLByte*>((char*)unfiltered.first), XMLString::stringLen(unfiltered.first), &outlen);\r
+            XMLByte *pos, *pos2;\r
+            for (pos=serialized, pos2=serialized; *pos2; pos2++)\r
+                if (isgraph(*pos2))\r
+                    *pos++=*pos2;\r
+            *pos=0;\r
+            setHeader("Shib-Attributes", reinterpret_cast<char*>(serialized));\r
+            XMLString::release(&serialized);\r
+        }\r
+\r
+        // Export the SAML AuthnMethod and the origin site name, and possibly the NameIdentifier.\r
+        setHeader("Shib-Origin-Site", m_cacheEntry->getProviderId());\r
+        setHeader("Shib-Identity-Provider", m_cacheEntry->getProviderId());\r
+        setHeader("Shib-Authentication-Method", m_cacheEntry->getAuthnContext());\r
+        \r
+        // Get the AAP providers, which contain the attribute policy info.\r
+        Iterator<IAAP*> provs=m_app->getAAPProviders();\r
+\r
+        // Export NameID?\r
+        while (provs.hasNext()) {\r
+            IAAP* aap=provs.next();\r
+            xmltooling::Locker locker(aap);\r
+            const XMLCh* format = sub.second->getNameIdentifier()->getFormat();\r
+            const IAttributeRule* rule=aap->lookup(format ? format : SAMLNameIdentifier::UNSPECIFIED);\r
+            if (rule && rule->getHeader()) {\r
+                auto_ptr_char form(format ? format : SAMLNameIdentifier::UNSPECIFIED);\r
+                auto_ptr_char nameid(sub.second->getNameIdentifier()->getName());\r
+                setHeader("Shib-NameIdentifier-Format", form.get());\r
+                if (!strcmp(rule->getHeader(),"REMOTE_USER"))\r
+                    setRemoteUser(nameid.get());\r
+                else\r
+                    setHeader(rule->getHeader(), nameid.get());\r
+            }\r
+        }\r
+        \r
+        setHeader("Shib-Application-ID", m_app->getId());\r
+    \r
+        // Export the attributes.\r
+        Iterator<SAMLAssertion*> a_iter(filtered.second ? filtered.second->getAssertions() : EMPTY(SAMLAssertion*));\r
+        while (a_iter.hasNext()) {\r
+            SAMLAssertion* assert=a_iter.next();\r
+            Iterator<SAMLStatement*> statements=assert->getStatements();\r
+            while (statements.hasNext()) {\r
+                SAMLAttributeStatement* astate=dynamic_cast<SAMLAttributeStatement*>(statements.next());\r
+                if (!astate)\r
+                    continue;\r
+                Iterator<SAMLAttribute*> attrs=astate->getAttributes();\r
+                while (attrs.hasNext()) {\r
+                    SAMLAttribute* attr=attrs.next();\r
+            \r
+                    // Are we supposed to export it?\r
+                    provs.reset();\r
+                    while (provs.hasNext()) {\r
+                        IAAP* aap=provs.next();\r
+                        xmltooling::Locker locker(aap);\r
+                        const IAttributeRule* rule=aap->lookup(attr->getName(),attr->getNamespace());\r
+                        if (!rule || !rule->getHeader())\r
+                            continue;\r
+                    \r
+                        Iterator<string> vals=attr->getSingleByteValues();\r
+                        if (!strcmp(rule->getHeader(),"REMOTE_USER") && vals.hasNext())\r
+                            setRemoteUser(vals.next().c_str());\r
+                        else {\r
+                            int it=0;\r
+                            string header = getSecureHeader(rule->getHeader());\r
+                            if (!header.empty())\r
+                                it++;\r
+                            for (; vals.hasNext(); it++) {\r
+                                string value = vals.next();\r
+                                for (string::size_type pos = value.find_first_of(";", string::size_type(0));\r
+                                        pos != string::npos;\r
+                                        pos = value.find_first_of(";", pos)) {\r
+                                    value.insert(pos, "\\");\r
+                                    pos += 2;\r
+                                }\r
+                                if (it)\r
+                                    header += ";";\r
+                                header += value;\r
+                            }\r
+                            setHeader(rule->getHeader(), header.c_str());\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+        }\r
+        */\r
+    \r
+        return make_pair(false,0);\r
+    }\r
+    catch (XMLToolingException& e) {\r
+        TemplateParameters tp;
+        tp.m_map["errorType"] = procState;\r
+        tp.m_map["errorText"] = e.what();\r
+        tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?'));\r
+        return make_pair(true,sendError(request, app, "rm", tp, &e));\r
+    }\r
+    catch (exception& e) {
+        TemplateParameters tp;
+        tp.m_map["errorType"] = procState;
+        tp.m_map["errorText"] = e.what();
+        tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?'));
+        return make_pair(true,sendError(request, app, "rm", tp));
+    }
+#ifndef _DEBUG\r
+    catch (...) {\r
+        TemplateParameters tp;
+        tp.m_map["errorType"] = procState;\r
+        tp.m_map["errorText"] = "Caught an unknown exception.";\r
+        tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?'));\r
+        return make_pair(true,sendError(request, app, "rm", tp));\r
+    }\r
+#endif\r
 }
 
 pair<bool,long> ServiceProvider::doHandler(SPRequest& request) const
 {
-    return make_pair(true,0);
+#ifdef _DEBUG
+    xmltooling::NDC ndc("doHandler");
+#endif
+
+    const Application* app=NULL;
+    const char* procState = "Shibboleth Handler Error";
+    string targetURL = request.getRequestURL();
+
+    try {
+        RequestMapper::Settings settings = request.getRequestSettings();
+        app = &(request.getApplication());
+
+        const char* handlerURL=request.getHandlerURL(targetURL.c_str());
+        if (!handlerURL)
+            throw ConfigurationException("Cannot determine handler from resource URL, check configuration.");
+
+        // Make sure we only process handler requests.
+        if (!strstr(targetURL.c_str(),handlerURL))
+            return make_pair(true, request.returnDecline());
+
+        const PropertySet* sessionProps=app->getPropertySet("Sessions");
+        if (!sessionProps)
+            throw ConfigurationException("Unable to map request to application session settings, check configuration.");
+
+        // Process incoming request.
+        pair<bool,bool> handlerSSL=sessionProps->getBool("handlerSSL");
+      
+        // Make sure this is SSL, if it should be
+        if ((!handlerSSL.first || handlerSSL.second) && strcmp(request.getScheme(),"https"))
+            throw FatalProfileException("Blocked non-SSL access to Shibboleth handler.");
+
+        // We dispatch based on our path info. We know the request URL begins with or equals the handler URL,
+        // so the path info is the next character (or null).
+        const Handler* handler=app->getHandler(targetURL.c_str() + strlen(handlerURL));
+        if (!handler)
+            throw BindingException("Shibboleth handler invoked at an unconfigured location.");
+
+        if (XMLHelper::isNodeNamed(handler->getElement(),samlconstants::SAML20MD_NS,AssertionConsumerService::LOCAL_NAME))
+            procState = "Session Creation Error";
+        else if (XMLString::equals(handler->getElement()->getLocalName(),SessionInitiator))
+            procState = "Session Initiator Error";
+        else if (XMLHelper::isNodeNamed(handler->getElement(),samlconstants::SAML20MD_NS,SingleLogoutService::LOCAL_NAME))
+            procState = "Session Termination Error";
+        else
+            procState = "Protocol Handler Error";
+        pair<bool,long> hret=handler->run(request);
+
+        // Did the handler run successfully?
+        if (hret.first)
+            return hret;
+       
+        throw BindingException("Configured Shibboleth handler failed to process the request.");
+    }
+    catch (MetadataException& e) {
+        TemplateParameters tp;
+        tp.m_map["errorText"] = e.what();
+        // See if a metadata error page is installed.
+        const PropertySet* props=app->getPropertySet("Errors");
+        if (props) {
+            pair<bool,const char*> p=props->getString("metadata");
+            if (p.first) {
+                tp.m_map["errorType"] = procState;
+                tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?'));
+                return make_pair(true,sendError(request, app, "metadata", tp, &e));
+            }
+        }
+        throw;
+    }
+    catch (XMLToolingException& e) {
+        TemplateParameters tp;
+        tp.m_map["errorType"] = procState;
+        tp.m_map["errorText"] = e.what();
+        tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?'));
+        return make_pair(true,sendError(request, app, "session", tp, &e));
+    }
+    catch (exception& e) {
+        TemplateParameters tp;
+        tp.m_map["errorType"] = procState;
+        tp.m_map["errorText"] = e.what();
+        tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?'));
+        return make_pair(true,sendError(request, app, "session", tp));
+    }
+#ifndef _DEBUG
+    catch (...) {
+        TemplateParameters tp;
+        tp.m_map["errorType"] = procState;
+        tp.m_map["errorText"] = "Caught an unknown exception.";
+        tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?'));
+        return make_pair(true,sendError(request, app, "session", tp));
+    }
+#endif
 }
index b6c55e1..bebe351 100644 (file)
@@ -33,6 +33,7 @@ namespace shibsp {
     class SHIBSP_API RequestMapper;
     class SHIBSP_API SessionCache;
     class SHIBSP_API SPRequest;
+    class SHIBSP_API TemplateParameters;
 
     /**
      * Interface to a Shibboleth ServiceProvider instance.
index 3ccdea9..64bbd8f 100644 (file)
                                        RelativePath=".\util\SPConstants.cpp"\r
                                        >\r
                                </File>\r
+                               <File\r
+                                       RelativePath=".\util\TemplateParameters.cpp"\r
+                                       >\r
+                               </File>\r
                        </Filter>\r
                        <Filter\r
                                Name="security"\r
                                        RelativePath=".\util\SPConstants.h"\r
                                        >\r
                                </File>\r
+                               <File\r
+                                       RelativePath=".\util\TemplateParameters.h"\r
+                                       >\r
+                               </File>\r
                        </Filter>\r
                        <Filter\r
                                Name="security"\r
diff --git a/shibsp/util/TemplateParameters.cpp b/shibsp/util/TemplateParameters.cpp
new file mode 100644 (file)
index 0000000..160c2fe
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *  Copyright 2001-2006 Internet2
+ * 
+ * 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
+ *
+ *     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.
+ */
+
+/**
+ * TemplateParameters.cpp
+ * 
+ * Supplies xmltooling TemplateEngine with additional parameters from a PropertySet. 
+ */
+
+#include "internal.h"
+#include "util/TemplateParameters.h"
+
+#include <ctime>
+
+using namespace shibsp;
+using namespace xmltooling;
+using namespace std;
+
+void TemplateParameters::setPropertySet(const PropertySet* props)
+{
+    m_props = props;
+
+    // Create a timestamp.
+    time_t now = time(NULL);
+#ifdef HAVE_CTIME_R
+    char timebuf[32];
+    m_map["now"] = ctime_r(&now,timebuf);
+#else
+    m_map["now"] = ctime(&now);
+#endif
+}
+
+const char* TemplateParameters::getParameter(const char* name) const
+{
+    const char* pch = TemplateEngine::TemplateParameters::getParameter(name);
+    if (pch || !m_props)
+        return pch;
+    pair<bool,const char*> p = m_props->getString(name);
+    return p.first ? p.second : NULL;
+}
diff --git a/shibsp/util/TemplateParameters.h b/shibsp/util/TemplateParameters.h
new file mode 100644 (file)
index 0000000..e276734
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ *  Copyright 2001-2006 Internet2
+ * 
+ * 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
+ *
+ *     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.
+ */
+
+/**
+ * @file shibsp/util/TemplateParameters.h
+ * 
+ * Supplies xmltooling TemplateEngine with additional parameters from a PropertySet. 
+ */
+
+#ifndef __shibsp_tempparams_h__
+#define __shibsp_tempparams_h__
+
+#include <shibsp/util/PropertySet.h>
+#include <xmltooling/util/TemplateEngine.h>
+
+namespace shibsp {
+
+    /**
+     * Supplies xmltooling TemplateEngine with additional parameters from a PropertySet.
+     */
+    class SHIBSP_API TemplateParameters : public xmltooling::TemplateEngine::TemplateParameters
+    {
+    public:
+        /**
+         * Constructor
+         * 
+         * @param props a PropertySet to supply additional parameters
+         */
+        TemplateParameters(const PropertySet* props=NULL) {
+            setPropertySet(props);
+        }
+
+        virtual ~TemplateParameters() {}
+        
+        /**
+         * Sets a PropertySet to supply additional parameters.
+         *  
+         * @param props a PropertySet to supply additional parameters
+         */
+        void setPropertySet(const PropertySet* props);
+        
+        const char* getParameter(const char* name) const;
+
+    private:
+        const PropertySet* m_props;
+    };
+};
+
+#endif /* __shibsp_tempparams_h__ */