Revise module for new APIs, lazy sessions.
authorcantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Mon, 22 Mar 2004 06:05:22 +0000 (06:05 +0000)
committercantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Mon, 22 Mar 2004 06:05:22 +0000 (06:05 +0000)
git-svn-id: https://svn.middleware.georgetown.edu/cpp-sp/trunk@891 cb58f699-b61c-0410-a6fe-9272a202ed29

isapi_shib/isapi_shib.cpp

index 3d8c755..781449a 100644 (file)
@@ -53,6 +53,8 @@
    8/23/02
 */
 
+#include "config_win32.h"
+
 // SAML Runtime
 #include <saml/saml.h>
 #include <shib/shib.h>
@@ -69,8 +71,6 @@
 #include <httpfilt.h>
 #include <httpext.h>
 
-#include <cgiparse.h>
-
 using namespace std;
 using namespace log4cpp;
 using namespace saml;
@@ -81,7 +81,8 @@ using namespace shibtarget;
 namespace {
     HINSTANCE g_hinstDLL;
     ShibTargetConfig* g_Config = NULL;
-    vector<string> g_Sites;
+    map<string,string> g_Sites;
+    bool g_bNormalizeRequest = true;
 }
 
 BOOL LogEvent(
@@ -122,6 +123,22 @@ extern "C" BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO* pVer)
     return TRUE;
 }
 
+extern "C" BOOL WINAPI TerminateExtension(DWORD)
+{
+    return TRUE;    // cleanup should happen when filter unloads
+}
+
+static const XMLCh host[] = { chLatin_h, chLatin_o, chLatin_s, chLatin_t, chNull };
+static const XMLCh id[] = { chLatin_i, chLatin_d, chNull };
+static const XMLCh Implementation[] =
+{ chLatin_I, chLatin_m, chLatin_p, chLatin_l, chLatin_e, chLatin_m, chLatin_e, chLatin_n, chLatin_t, chLatin_a, chLatin_t, chLatin_i, chLatin_o, chLatin_n, chNull };
+static const XMLCh ISAPI[] = { chLatin_I, chLatin_S, chLatin_A, chLatin_P, chLatin_I, chNull };
+static const XMLCh normalizeRequest[] =
+{ chLatin_n, chLatin_o, chLatin_r, chLatin_m, chLatin_a, chLatin_l, chLatin_i, chLatin_z, chLatin_e,
+  chLatin_R, chLatin_e, chLatin_q, chLatin_u, chLatin_e, chLatin_s, chLatin_t, chNull
+};
+static const XMLCh Site[] = { chLatin_S, chLatin_i, chLatin_t, chLatin_e, chNull };
+
 extern "C" BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer)
 {
     if (!pVer)
@@ -129,47 +146,51 @@ extern "C" BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer)
 
     try
     {
-        ShibTargetConfig::preinit();
-        g_Config = &(ShibTargetConfig::init(SHIBTARGET_SHIRE, getenv("SHIBCONFIG")));
-        ShibINI& ini = g_Config->getINI();
-
-        Category& log=Category::getInstance("isapi_shib.GetFilterVersion");
-
-        // Read site-specific settings for each instance ID we can find.
-        unsigned short i=1;
-        char iid[8];
-        sprintf(iid,"%u",i++);
-        string hostname;
-        while (ini.get_tag("isapi",iid,false,&hostname))
-        {
-            log.info("configuring for site ID (%d), hostname (%s)",i-1,hostname.empty() ? "null" : hostname.c_str());
-
-            // If no section exists for the host, mark it as a "skip" site.
-            if (hostname == "skip")
-            {
-                log.info("skipping site ID (%d)",i-1);
-                hostname.erase();
+        LPCSTR schemadir=getenv("SHIBSCHEMAS");
+        if (!schemadir)
+            schemadir=SHIB_SCHEMAS;
+        LPCSTR config=getenv("SHIBCONFIG");
+        if (!config)
+            config=SHIB_CONFIG;
+        g_Config=&ShibTargetConfig::getConfig();
+        g_Config->setFeatures(
+            ShibTargetConfig::Listener |
+            ShibTargetConfig::Metadata |
+            ShibTargetConfig::AAP |
+            ShibTargetConfig::RequestMapper |
+            ShibTargetConfig::SHIREExtensions
+            );
+        if (!g_Config->init(schemadir,config)) {
+            LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL,
+                    "Filter startup failed during initialization, check shire log for help.");
+            return FALSE;
+        }
+        
+        // Access the implementation-specifics for site mappings.
+        IConfig* conf=g_Config->getINI();
+        Locker locker(conf);
+        const IPropertySet* props=conf->getPropertySet("SHIRE");
+        if (props) {
+            const DOMElement* impl=saml::XML::getFirstChildElement(
+                props->getElement(),ShibTargetConfig::SHIBTARGET_NS,Implementation
+                );
+            if (impl && (impl=saml::XML::getFirstChildElement(impl,ShibTargetConfig::SHIBTARGET_NS,ISAPI))) {
+                const XMLCh* flag=impl->getAttributeNS(NULL,normalizeRequest);
+                g_bNormalizeRequest=(!flag || !*flag || *flag==chDigit_1 || *flag==chLatin_t);
+                impl=saml::XML::getFirstChildElement(impl,ShibTargetConfig::SHIBTARGET_NS,Site);
+                while (impl) {
+                    auto_ptr_char id(impl->getAttributeNS(NULL,id));
+                    auto_ptr_char host(impl->getAttributeNS(NULL,host));
+                    if (id.get() && host.get())
+                        g_Sites[id.get()]=host.get();
+                    impl=saml::XML::getNextSiblingElement(impl,ShibTargetConfig::SHIBTARGET_NS,Site);
+                }
             }
-
-            g_Sites.push_back(hostname);
-            sprintf(iid,"%u",i++);
-            hostname.erase();
         }
     }
-    catch (SAMLException&)
-    {
-        LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL,
-                "Filter startup failed with SAML exception, check shire log for help.");
-        return FALSE;
-    }
-    catch (runtime_error& e)
-    {
-        LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, e.what());
-        return FALSE;
-    }
     catch (...)
     {
-        LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "Filter startup failed with unexpected exception.");
+        LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "Filter startup failed with an exception.");
         return FALSE;
     }
 
@@ -184,11 +205,6 @@ extern "C" BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer)
     return TRUE;
 }
 
-extern "C" BOOL WINAPI TerminateExtension(DWORD)
-{
-    return TRUE;    // cleanup should happen when filter unloads
-}
-
 extern "C" BOOL WINAPI TerminateFilter(DWORD)
 {
     if (g_Config)
@@ -309,71 +325,34 @@ void GetHeader(PHTTP_FILTER_PREPROC_HEADERS pn, PHTTP_FILTER_CONTEXT pfc,
         throw ERROR_NO_DATA;
 }
 
-inline char hexchar(unsigned short s)
-{
-    return (s<=9) ? ('0' + s) : ('A' + s - 10);
-}
-
-string url_encode(const char* url) throw (bad_alloc)
-{
-    static char badchars[]="\"\\+<>#%{}|^~[]`;/?:@=&";
-    string s;
-    for (const char* pch=url; *pch; pch++)
-    {
-        if (strchr(badchars,*pch)!=NULL || *pch<=0x1F || *pch>=0x7F)
-            s=s + '%' + hexchar(*pch >> 4) + hexchar(*pch & 0x0F);
-        else
-            s+=*pch;
-    }
-    return s;
-}
-
-void get_target_and_appid(
-    PHTTP_FILTER_CONTEXT pfc, PHTTP_FILTER_PREPROC_HEADERS pn, const char* hostname, string& target, string& appid
+IRequestMapper::Settings map_request(
+    PHTTP_FILTER_CONTEXT pfc, PHTTP_FILTER_PREPROC_HEADERS pn, IRequestMapper* mapper, const char* hostname, string& target
     )
 {
+    dynabuf method(10);
     dynabuf port(10);
     dynabuf url(256);
+    GetServerVariable(pfc,"REQUEST_METHOD",method,10);
     GetServerVariable(pfc,"SERVER_PORT",port,10);
     GetHeader(pn,pfc,"url",url,256,false);
     
-    // First get the appid using the normalized hostname.
-    ApplicationMapper mapper;
-    appid = mapper->getApplicationFromParsedURL((pfc->fIsSecurePort ? "https" : "http"), hostname, atoi(port), url);
-
-    target=static_cast<char*>(url);
+    if (!url.empty())
+        target=static_cast<char*>(url);
     if (port!=(pfc->fIsSecurePort ? "443" : "80"))
         target = ':' + static_cast<char*>(port) + target;
 
-    // For the target, we use the "normalizeRequest" tag to decide how to set the server's name.
-    string tag;
-    if (g_Config->getINI().get_tag(appid,"normalizeRequest",true,&tag) && ShibINI::boolean(tag))
-    {
-        target=string(pfc->fIsSecurePort ? "https://" : "http://") + hostname + target;
+    if (g_bNormalizeRequest) {
+        target = string(pfc->fIsSecurePort ? "https://" : "http://") + hostname + target;
+        return mapper->getSettingsFromParsedURL(method,hostname,strtoul(port,NULL,10),url);
     }
-    else
-    {
-        GetServerVariable(pfc,"SERVER_NAME",url);
-        target=string(pfc->fIsSecurePort ? "https://" : "http://") + static_cast<char*>(url) + target;
+    else {
+        dynabuf name(64);
+        GetServerVariable(pfc,"SERVER_NAME",name,64);
+        target = string(pfc->fIsSecurePort ? "https://" : "http://") + static_cast<char*>(name) + target;
+        return mapper->getSettingsFromParsedURL(method,name,strtoul(port,NULL,10),url);
     }
 }
 
-string get_shire_location(const char* application_id, const char* target)
-{
-    string shireURL;
-    if (g_Config->getINI().get_tag(application_id,"shireURL",true,&shireURL) && !shireURL.empty())
-    {
-        if (shireURL[0]!='/')
-            return shireURL;
-        const char* colon=strchr(target,':');
-        const char* slash=strchr(colon+3,'/');
-        string s(target,slash-target);
-        s+=shireURL;
-        return s;
-    }
-    return shireURL;
-}
-
 DWORD WriteClientError(PHTTP_FILTER_CONTEXT pfc, const char* msg)
 {
     LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, msg);
@@ -392,19 +371,29 @@ DWORD WriteClientError(PHTTP_FILTER_CONTEXT pfc, const char* msg)
     return SF_STATUS_REQ_FINISHED;
 }
 
-DWORD WriteClientError(PHTTP_FILTER_CONTEXT pfc, const char* filename, ShibMLP& mlp)
+DWORD WriteClientError(PHTTP_FILTER_CONTEXT pfc, const IApplication* app, const char* page, ShibMLP& mlp)
 {
-    ifstream infile(filename);
-    if (!infile)
-        return WriteClientError(pfc,"Unable to open error template, check settings.");   
-    string res = mlp.run(infile);
+    const IPropertySet* props=app->getPropertySet("Errors");
+    if (props) {
+        pair<bool,const char*> p=props->getString(page);
+        if (p.first) {
+            ifstream infile(p.second);
+            if (!infile.fail()) {
+                const char* res = mlp.run(infile);
+                if (res) {
+                    static const char* ctype="Content-Type: text/html\r\n";
+                    pfc->AddResponseHeaders(pfc,const_cast<char*>(ctype),0);
+                    pfc->ServerSupportFunction(pfc,SF_REQ_SEND_RESPONSE_HEADER,"200 OK",0,0);
+                    DWORD resplen=strlen(res);
+                    pfc->WriteClient(pfc,(LPVOID)res,&resplen,0);
+                    return SF_STATUS_REQ_FINISHED;
+                }
+            }
+        }
+    }
 
-    static const char* ctype="Content-Type: text/html\r\n";
-    pfc->AddResponseHeaders(pfc,const_cast<char*>(ctype),0);
-    pfc->ServerSupportFunction(pfc,SF_REQ_SEND_RESPONSE_HEADER,"200 OK",0,0);
-    DWORD resplen=res.length();
-    pfc->WriteClient(pfc,(LPVOID)res.c_str(),&resplen,0);
-    return SF_STATUS_REQ_FINISHED;
+    LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "Filter unable to open error template.");
+    return WriteClientError(pfc,"Unable to open error template, check settings.");
 }
 
 extern "C" DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificationType, LPVOID pvNotification)
@@ -422,135 +411,106 @@ extern "C" DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificat
     {
         // Determine web site number. This can't really fail, I don't think.
         dynabuf buf(128);
-        ULONG site_id=0;
         GetServerVariable(pfc,"INSTANCE_ID",buf,10);
-        if ((site_id=strtoul(buf,NULL,10))==0)
-            return WriteClientError(pfc,"IIS site instance appears to be invalid.");
-
-        // Match site instance to site settings.
-        if (site_id>g_Sites.size() || g_Sites[site_id-1].length()==0)
-            return SF_STATUS_REQ_NEXT_NOTIFICATION;
-        string& site=g_Sites[site_id-1];
-        
-        string application_id;
-        string target_url;
-        get_target_and_appid(pfc,pn,site.c_str(),target_url,application_id);
-        string shire_url=get_shire_location(application_id.c_str(),target_url.c_str());
-
-        // If the user is accessing the SHIRE acceptance point, pass it on.
-        if (target_url.find(shire_url)!=string::npos)
-            return SF_STATUS_REQ_NEXT_NOTIFICATION;
 
-        // Now check the policy for this application.
-        string tag;
-        ShibINI& ini=g_Config->getINI();
-        if (!ini.get_tag(application_id,"requireSession",true,&tag) || !ShibINI::boolean(tag))
+        // Match site instance to host name, skip if no match.
+        map<string,string>::const_iterator map_i=g_Sites.find(static_cast<char*>(buf));
+        if (map_i==g_Sites.end())
             return SF_STATUS_REQ_NEXT_NOTIFICATION;
-
-        // SSL content check.
-        if (ini.get_tag(application_id,"contentSSLOnly",true,&tag) && ShibINI::boolean(tag) && !pfc->fIsSecurePort)
-        {
-            return WriteClientError(pfc,
-                "This server is configured to deny non-SSL requests for secure resources. "
-                "Try your request again using https instead of http.");
-        }
+            
+        const string& site=map_i->second;
 
         ostringstream threadid;
-        threadid << "[" << getpid() << "] shire" << '\0';
+        threadid << "[" << getpid() << "] isapi_shib" << '\0';
         saml::NDC ndc(threadid.str().c_str());
+        
+        // We lock the configuration system for the duration.
+        IConfig* conf=g_Config->getINI();
+        Locker locker(conf);
+        
+        // Map request to application and content settings.
+        string targeturl;
+        IRequestMapper* mapper=conf->getRequestMapper();
+        Locker locker2(mapper);
+        IRequestMapper::Settings settings=map_request(pfc,pn,mapper,site.c_str(),targeturl);
+        pair<bool,const char*> application_id=settings.first->getString("applicationId");
+        const IApplication* application=conf->getApplication(application_id.second);
+        const IPropertySet* sessionProps=application ? application->getPropertySet("Sessions") : NULL;
+        if (!application || !sessionProps)
+            return WriteClientError(pfc,"Unable to map request to application session settings, check configuration.");
+        
+        // Declare SHIRE object for this request.
+        SHIRE shire(application);
 
-        // Set SHIRE policies.
-        SHIREConfig config;
-        config.checkIPAddress = (ini.get_tag(application_id,"checkIPAddress",true,&tag) && ShibINI::boolean(tag));
-        config.lifetime=config.timeout=0;
-        tag.erase();
-        if (ini.get_tag(application_id, "authLifetime", true, &tag))
-            config.lifetime=strtoul(tag.c_str(),NULL,10);
-        tag.erase();
-        if (ini.get_tag(application_id, "authTimeout", true, &tag))
-            config.timeout=strtoul(tag.c_str(),NULL,10);
-
-        // Pull the config data we need to handle the various possible conditions.
-        string shib_cookie;
-        if (!ini.get_tag(application_id, "cookieName", true, &shib_cookie))
-            return WriteClientError(pfc,"The cookieName configuration setting is missing, check configuration.");
-    
-        string wayfLocation;
-        if (!ini.get_tag(application_id, "wayfURL", true, &wayfLocation))
-            return WriteClientError(pfc,"The wayfURL configuration setting is missing, check configuration.");
-    
-        string shireError;
-        if (!ini.get_tag(application_id, "shireError", true, &shireError))
-            return WriteClientError(pfc,"The shireError configuration setting is missing, check configuration.");
+        // If the user is accessing the SHIRE acceptance point, pass it on.
+        if (targeturl.find(shire.getShireURL(targeturl.c_str()))!=string::npos)
+            return SF_STATUS_REQ_NEXT_NOTIFICATION;
 
-        string accessError;
-        if (!ini.get_tag(application_id, "accessError", true, &shireError))
-            return WriteClientError(pfc,"The accessError configuration setting is missing, check configuration.");
-        
-        SHIRE shire(config, shire_url.c_str());
+        // Now check the policy for this request.
+        pair<bool,bool> requireSession=settings.first->getBool("requireSession");
+        pair<bool,const char*> shib_cookie=sessionProps->getString("cookieName");
+        if (!shib_cookie.first)
+            return WriteClientError(pfc,"No session cookie name defined for this application, check configuration.");
 
-        // Check for authentication cookie.
+        // Check for session cookie.
         const char* session_id=NULL;
         GetHeader(pn,pfc,"Cookie:",buf,128,false);
         Category::getInstance("isapi_shib.HttpFilterProc").debug("cookie header is {%s}",(const char*)buf);
-        if (buf.empty() || !(session_id=strstr(buf,shib_cookie.c_str())) || *(session_id+shib_cookie.length())!='=')
-        {
-            // Redirect to WAYF.
-            char timebuf[16];
-            sprintf(timebuf,"%u",time(NULL));
-            string wayf("Location: ");
-            wayf+=wayfLocation + "?shire=" + url_encode(shire_url.c_str()) + "&target=" + url_encode(target_url.c_str()) +
-                "&time=" + timebuf + "&providerId=" + application_id + "\r\n";
-            // Insert the headers.
-            pfc->AddResponseHeaders(pfc,const_cast<char*>(wayf.c_str()),0);
+        if (!buf.empty() && (session_id=strstr(buf,shib_cookie.second))) {
+            session_id+=strlen(shib_cookie.second) + 1;   /* Skip over the '=' */
+            char* cookieend=strchr(session_id,';');
+            if (cookieend)
+                *cookieend = '\0';    /* Ignore anyting after a ; */
+        }
+        
+        if (!session_id || !*session_id) {
+            // If no session required, bail now.
+            if (!requireSession.second)
+                return SF_STATUS_REQ_NEXT_NOTIFICATION;
+    
+            // No acceptable cookie, and we require a session.  Generate an AuthnRequest.
+            string loc("Location: ");
+            loc+=shire.getAuthnRequest(targeturl.c_str());
+            pfc->AddResponseHeaders(pfc,const_cast<char*>(loc.c_str()),0);
             pfc->ServerSupportFunction(pfc,SF_REQ_SEND_RESPONSE_HEADER,"302 Please Wait",0,0);
             return SF_STATUS_REQ_FINISHED;
         }
 
-        session_id+=shib_cookie.length() + 1;  /* Skip over the '=' */
-        char* cookieend=strchr(session_id,';');
-        if (cookieend)
-            *cookieend = '\0'; /* Ignore anyting after a ; */
-  
         // Make sure this session is still valid.
         RPCError* status = NULL;
-        ShibMLP markupProcessor;
-        bool has_tag = ini.get_tag(application_id, "supportContact", true, &tag);
-        markupProcessor.insert("supportContact", has_tag ? tag : "");
-        has_tag = ini.get_tag(application_id, "logoLocation", true, &tag);
-        markupProcessor.insert("logoLocation", has_tag ? tag : "");
-        markupProcessor.insert("requestURL", target_url);
+        ShibMLP markupProcessor(application);
+        markupProcessor.insert("requestURL", targeturl);
     
         dynabuf abuf(16);
         GetServerVariable(pfc,"REMOTE_ADDR",abuf,16);
         try {
-            status = shire.sessionIsValid(session_id, abuf, application_id.c_str());
+            status = shire.sessionIsValid(session_id, abuf);
         }
         catch (ShibTargetException &e) {
-            markupProcessor.insert("errorType", "SHIRE Processing Error");
+            markupProcessor.insert("errorType", "Session Processing Error");
             markupProcessor.insert("errorText", e.what());
             markupProcessor.insert("errorDesc", "An error occurred while processing your request.");
-            return WriteClientError(pfc, shireError.c_str(), markupProcessor);
+            return WriteClientError(pfc, application, "shire", markupProcessor);
         }
+#ifndef _DEBUG
         catch (...) {
-            markupProcessor.insert("errorType", "SHIRE Processing Error");
+            markupProcessor.insert("errorType", "Session Processing Error");
             markupProcessor.insert("errorText", "Unexpected Exception");
             markupProcessor.insert("errorDesc", "An error occurred while processing your request.");
-            return WriteClientError(pfc, shireError.c_str(), markupProcessor);
+            return WriteClientError(pfc, application, "shire", markupProcessor);
         }
-    
+#endif
+
         // Check the status
         if (status->isError()) {
-            if (status->isRetryable()) {
-                // Redirect to WAYF.
+            if (!requireSession.second)
+                return SF_STATUS_REQ_NEXT_NOTIFICATION;
+            else if (status->isRetryable()) {
+                // Oops, session is invalid. Generate AuthnRequest.
                 delete status;
-                char timebuf[16];
-                sprintf(timebuf,"%u",time(NULL));
-                string wayf("Location: ");
-                wayf+=wayfLocation + "?shire=" + url_encode(shire_url.c_str()) + "&target=" + url_encode(target_url.c_str()) +
-                    "&time=" + timebuf + "&providerId=" + application_id + "\r\n";
-                // Insert the headers.
-                pfc->AddResponseHeaders(pfc,const_cast<char*>(wayf.c_str()),0);
+                string loc("Location: ");
+                loc+=shire.getAuthnRequest(targeturl.c_str());
+                pfc->AddResponseHeaders(pfc,const_cast<char*>(loc.c_str()),0);
                 pfc->ServerSupportFunction(pfc,SF_REQ_SEND_RESPONSE_HEADER,"302 Please Wait",0,0);
                 return SF_STATUS_REQ_FINISHED;
             }
@@ -558,82 +518,86 @@ extern "C" DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificat
                 // return the error page to the user
                 markupProcessor.insert(*status);
                 delete status;
-                return WriteClientError(pfc, shireError.c_str(), markupProcessor);
+                return WriteClientError(pfc, application, "shire", markupProcessor);
             }
         }
         delete status;
     
         // Move to RM phase.
-        RMConfig rm_config;
-        rm_config.checkIPAddress = config.checkIPAddress;
-        RM rm(rm_config);
-
-        // Get the attributes.
+        RM rm(application);
         vector<SAMLAssertion*> assertions;
         SAMLAuthenticationStatement* sso_statement=NULL;
-        status = rm.getAssertions(session_id, buf, application_id.c_str(), assertions, &sso_statement);
+
+        try {
+            status = rm.getAssertions(session_id, abuf, assertions, &sso_statement);
+        }
+        catch (ShibTargetException &e) {
+            markupProcessor.insert("errorType", "Attribute Processing Error");
+            markupProcessor.insert("errorText", e.what());
+            markupProcessor.insert("errorDesc", "An error occurred while processing your request.");
+            return WriteClientError(pfc, application, "rm", markupProcessor);
+        }
+    #ifndef _DEBUG
+        catch (...) {
+            markupProcessor.insert("errorType", "Attribute Processing Error");
+            markupProcessor.insert("errorText", "Unexpected Exception");
+            markupProcessor.insert("errorDesc", "An error occurred while processing your request.");
+            return WriteClientError(pfc, application, "rm", markupProcessor);
+        }
+    #endif
     
         if (status->isError()) {
-            string rmError;
-            if (!ini.get_tag(application_id, "rmError", true, &shireError))
-                return WriteClientError(pfc,"The rmError configuration setting is missing, check configuration.");
-    
             markupProcessor.insert(*status);
             delete status;
-            return WriteClientError(pfc, rmError.c_str(), markupProcessor);
+            return WriteClientError(pfc, application, "rm", markupProcessor);
         }
         delete status;
 
-        // Only allow a single assertion...
-        if (assertions.size() > 1) {
-            for (int k = 0; k < assertions.size(); k++)
-              delete assertions[k];
-            delete sso_statement;
-            return WriteClientError(pfc, accessError.c_str(), markupProcessor);
+        // Do we have an access control plugin?
+        if (settings.second) {
+            Locker acllock(settings.second);
+            if (!settings.second->authorized(assertions)) {
+                for (int k = 0; k < assertions.size(); k++)
+                    delete assertions[k];
+                delete sso_statement;
+                return WriteClientError(pfc, application, "access", markupProcessor);
+            }
         }
 
         // Get the AAP providers, which contain the attribute policy info.
-        Iterator<IAAP*> provs=g_Config->getAAPProviders();
+        Iterator<IAAP*> provs=application->getAAPProviders();
     
         // Clear out the list of mapped attributes
-        while (provs.hasNext())
-        {
+        while (provs.hasNext()) {
             IAAP* aap=provs.next();
             aap->lock();
-            try
-            {
+            try {
                 Iterator<const IAttributeRule*> rules=aap->getAttributeRules();
-                while (rules.hasNext())
-                {
+                while (rules.hasNext()) {
                     const char* header=rules.next()->getHeader();
                     if (header)
                         pn->SetHeader(pfc,const_cast<char*>(header),"");
                 }
             }
-            catch(...)
-            {
+            catch(...) {
                 aap->unlock();
                 for (int k = 0; k < assertions.size(); k++)
                   delete assertions[k];
                 delete sso_statement;
-                throw;
+                markupProcessor.insert("errorType", "Attribute Processing Error");
+                markupProcessor.insert("errorText", "Unexpected Exception");
+                markupProcessor.insert("errorDesc", "An error occurred while processing your request.");
+                return WriteClientError(pfc, application, "rm", markupProcessor);
             }
             aap->unlock();
         }
         provs.reset();
 
-        // Clear relevant headers.
+        // Maybe export the first assertion.
         pn->SetHeader(pfc,"remote-user:","");
         pn->SetHeader(pfc,"Shib-Attributes:","");
-        pn->SetHeader(pfc,"Shib-Origin-Site:","");
-        pn->SetHeader(pfc,"Shib-Authentication-Method:","");
-
-        pn->SetHeader(pfc,"Shib-Application-ID:","");
-        pn->SetHeader(pfc,"Shib-Application-ID:",const_cast<char*>(application_id.c_str()));
-
-        // Maybe export the assertion.
-        if (ini.get_tag(application_id,"exportAssertion",true,&tag) && ShibINI::boolean(tag))
-        {
+        pair<bool,bool> exp=settings.first->getBool("exportAssertion");
+        if (exp.first && exp.second && assertions.size()) {
             string assertion;
             RM::serialize(*(assertions[0]), assertion);
             string::size_type lfeed;
@@ -642,14 +606,20 @@ extern "C" DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificat
             pn->SetHeader(pfc,"Shib-Attributes:",const_cast<char*>(assertion.c_str()));
         }
         
-        if (sso_statement)
-        {
+        pn->SetHeader(pfc,"Shib-Origin-Site:","");
+        pn->SetHeader(pfc,"Shib-Authentication-Method:","");
+
+        // Export the SAML AuthnMethod and the origin site name.
+        if (sso_statement) {
             auto_ptr_char os(sso_statement->getSubject()->getNameQualifier());
             auto_ptr_char am(sso_statement->getAuthMethod());
             pn->SetHeader(pfc,"Shib-Origin-Site:", const_cast<char*>(os.get()));
             pn->SetHeader(pfc,"Shib-Authentication-Method:", const_cast<char*>(am.get()));
         }
 
+        pn->SetHeader(pfc,"Shib-Application-ID:","");
+        pn->SetHeader(pfc,"Shib-Application-ID:",const_cast<char*>(application_id.second));
+
         // Export the attributes.
         Iterator<SAMLAssertion*> a_iter(assertions);
         while (a_iter.hasNext()) {
@@ -664,7 +634,7 @@ extern "C" DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificat
                     SAMLAttribute* attr=attrs.next();
         
                     // Are we supposed to export it?
-                    AAP wrapper(g_Config->getAAPProviders(),attr->getName(),attr->getNamespace());
+                    AAP wrapper(application->getAAPProviders(),attr->getName(),attr->getNamespace());
                     if (wrapper.fail())
                         continue;
                 
@@ -677,10 +647,19 @@ extern "C" DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificat
                             strcpy(static_cast<char*>(pfc->pFilterContext),principal);
                     }
                     else {
+                        int it=0;
                         string header;
-                        for (int it = 0; vals.hasNext(); it++) {
+                        string hname=string(wrapper->getHeader()) + ':';
+                        GetHeader(pn,pfc,const_cast<char*>(hname.c_str()),buf,256,false);
+                        if (buf.empty())
+                            header=buf;
+                        else
+                            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)) {
+                            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;
                             }
@@ -689,8 +668,7 @@ extern "C" DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificat
                             else
                                 header=header + ';' + value;
                         }
-                        string hname2=string(wrapper->getHeader()) + ':';
-                        pn->SetHeader(pfc,const_cast<char*>(hname2.c_str()),const_cast<char*>(header.c_str()));
+                        pn->SetHeader(pfc,const_cast<char*>(hname.c_str()),const_cast<char*>(header.c_str()));
                        }
                 }
             }
@@ -703,26 +681,25 @@ extern "C" DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificat
 
         return SF_STATUS_REQ_NEXT_NOTIFICATION;
     }
-    catch(bad_alloc)
-    {
+    catch(bad_alloc) {
         return WriteClientError(pfc,"Out of Memory");
     }
-    catch(DWORD e)
-    {
+    catch(DWORD e) {
         if (e==ERROR_NO_DATA)
             return WriteClientError(pfc,"A required variable or header was empty.");
         else
             return WriteClientError(pfc,"Server detected unexpected IIS error.");
     }
-    catch(...)
-    {
+    catch(...) {
         return WriteClientError(pfc,"Server caught an unknown exception.");
     }
 
-    return WriteClientError(pfc,"Server reached unreachable code!");
+    return WriteClientError(pfc,"Server reached unreachable code, save my walrus!");
 }
 
-void get_target_and_appid(LPEXTENSION_CONTROL_BLOCK lpECB, const char* hostname, string& target, string& appid)
+IRequestMapper::Settings map_request(
+    LPEXTENSION_CONTROL_BLOCK lpECB, IRequestMapper* mapper, const char* hostname, string& target
+    )
 {
     dynabuf ssl(5);
     dynabuf port(10);
@@ -732,24 +709,20 @@ void get_target_and_appid(LPEXTENSION_CONTROL_BLOCK lpECB, const char* hostname,
     GetServerVariable(lpECB,"URL",url,255);
     bool SSL=(ssl=="on");
     
-    // First get the appid using the normalized hostname.
-    ApplicationMapper mapper;
-    appid = mapper->getApplicationFromParsedURL((SSL ? "https" : "http"), hostname, atoi(port), url);
-
-    target=static_cast<char*>(url);
+    if (!url.empty())
+        target=static_cast<char*>(url);
     if (port!=(SSL ? "443" : "80"))
         target = ':' + static_cast<char*>(port) + target;
 
-    // For the target, we use the "normalizeRequest" tag to decide how to set the server's name.
-    string tag;
-    if (g_Config->getINI().get_tag(appid,"normalizeRequest",true,&tag) && ShibINI::boolean(tag))
-    {
-        target=string(SSL ? "https://" : "http://") + hostname + target;
+    if (g_bNormalizeRequest) {
+        target = string(SSL ? "https://" : "http://") + hostname + target;
+        return mapper->getSettingsFromParsedURL(lpECB->lpszMethod,hostname,strtoul(port,NULL,10),url);
     }
-    else
-    {
-        GetServerVariable(lpECB,"SERVER_NAME",url);
-        target=string(SSL ? "https://" : "http://") + static_cast<char*>(url) + target;
+    else {
+        dynabuf name(64);
+        GetServerVariable(lpECB,"SERVER_NAME",name,64);
+        target = string(SSL ? "https://" : "http://") + static_cast<char*>(name) + target;
+        return mapper->getSettingsFromParsedURL(lpECB->lpszMethod,name,strtoul(port,NULL,10),url);
     }
 }
 
@@ -769,134 +742,153 @@ DWORD WriteClientError(LPEXTENSION_CONTROL_BLOCK lpECB, const char* msg)
     return HSE_STATUS_SUCCESS;
 }
 
-DWORD WriteClientError(LPEXTENSION_CONTROL_BLOCK lpECB, const char* filename, ShibMLP& mlp)
+DWORD WriteClientError(LPEXTENSION_CONTROL_BLOCK lpECB, const IApplication* app, const char* page, ShibMLP& mlp)
 {
-    ifstream infile(filename);
-    if (!infile)
-        return WriteClientError(lpECB,"Unable to open error template, check settings.");   
-
-    string res = mlp.run(infile);
-    static const char* ctype="Content-Type: text/html\r\n";
-    lpECB->ServerSupportFunction(lpECB->ConnID,HSE_REQ_SEND_RESPONSE_HEADER,"200 OK",0,(LPDWORD)ctype);
-    DWORD resplen=res.length();
-    lpECB->WriteClient(lpECB->ConnID,(LPVOID)res.c_str(),&resplen,0);
-    return HSE_STATUS_SUCCESS;
+    const IPropertySet* props=app->getPropertySet("Errors");
+    if (props) {
+        pair<bool,const char*> p=props->getString(page);
+        if (p.first) {
+            ifstream infile(p.second);
+            if (!infile.fail()) {
+                const char* res = mlp.run(infile);
+                if (res) {
+                    static const char* ctype="Content-Type: text/html\r\n";
+                    lpECB->ServerSupportFunction(lpECB->ConnID,HSE_REQ_SEND_RESPONSE_HEADER,"200 OK",0,(LPDWORD)ctype);
+                    DWORD resplen=strlen(res);
+                    lpECB->WriteClient(lpECB->ConnID,(LPVOID)res,&resplen,0);
+                    return HSE_STATUS_SUCCESS;
+                }
+            }
+        }
+    }
+    LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "Extension unable to open error template.");
+    return WriteClientError(lpECB,"Unable to open error template, check settings.");
 }
 
 extern "C" DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB)
 {
-    ostringstream threadid;
-    threadid << "[" << getpid() << "] shire" << '\0';
-    saml::NDC ndc(threadid.str().c_str());
-
-    ShibINI& ini = g_Config->getINI();
-    string shireError;
-    ShibMLP markupProcessor;
-
+    const IApplication* application=NULL;
     try
     {
+        ostringstream threadid;
+        threadid << "[" << getpid() << "] shire_handler" << '\0';
+        saml::NDC ndc(threadid.str().c_str());
+
         // Determine web site number. This can't really fail, I don't think.
         dynabuf buf(128);
-        ULONG site_id=0;
         GetServerVariable(lpECB,"INSTANCE_ID",buf,10);
-        if ((site_id=strtoul(buf,NULL,10))==0)
-            return WriteClientError(lpECB,"IIS site instance appears to be invalid.");
 
-        // Match site instance to site settings.
-        if (site_id>g_Sites.size() || g_Sites[site_id-1].length()==0)
+        // Match site instance to host name, skip if no match.
+        map<string,string>::const_iterator map_i=g_Sites.find(static_cast<char*>(buf));
+        if (map_i==g_Sites.end())
             return WriteClientError(lpECB,"Shibboleth filter not configured for this web site.");
-        string& site=g_Sites[site_id-1];
-
-        string target_url,application_id;
-        get_target_and_appid(lpECB,site.c_str(),target_url,application_id);
-
-        if (!ini.get_tag(application_id, "shireError", true, &shireError))
-            return WriteClientError(lpECB,"The shireError configuration setting is missing, check configuration.");
-
-        string shire_url = target_url;
-
-        // Set SHIRE policies.
-        SHIREConfig config;
-        string tag;
-        config.checkIPAddress = (ini.get_tag(application_id,"checkIPAddress",true,&tag) && ShibINI::boolean(tag));
-        config.lifetime=config.timeout=0;
-        tag.erase();
-        if (ini.get_tag(application_id, "authLifetime", true, &tag))
-            config.lifetime=strtoul(tag.c_str(),NULL,10);
-        tag.erase();
-        if (ini.get_tag(application_id, "authTimeout", true, &tag))
-            config.timeout=strtoul(tag.c_str(),NULL,10);
-
-        // Pull the config data we need to handle the various possible conditions.
-        string shib_cookie;
-        if (!ini.get_tag(application_id, "cookieName", true, &shib_cookie))
-            return WriteClientError(lpECB,"The cookieName configuration setting is missing, check configuration.");
-    
-        string wayfLocation;
-        if (!ini.get_tag(application_id, "wayfURL", true, &wayfLocation))
-            return WriteClientError(lpECB,"The wayfURL configuration setting is missing, check configuration.");
-    
-        bool has_tag = ini.get_tag(application_id, "supportContact", true, &tag);
-        markupProcessor.insert("supportContact", has_tag ? tag : "");
-        has_tag = ini.get_tag(application_id, "logoLocation", true, &tag);
-        markupProcessor.insert("logoLocation", has_tag ? tag : "");
-        markupProcessor.insert("requestURL", target_url.c_str());
-  
-        SHIRE shire(config, shire_url.c_str());
-
-        // Process SHIRE POST
-        if (ini.get_tag(application_id, "shireSSLOnly", true, &tag) && ShibINI::boolean(tag))
-        {
-            // Make sure this is SSL, if it should be.
+            
+        const string& site=map_i->second;
+
+        // We lock the configuration system for the duration.
+        IConfig* conf=g_Config->getINI();
+        Locker locker(conf);
+        
+        // Map request to application and content settings.
+        string targeturl;
+        IRequestMapper* mapper=conf->getRequestMapper();
+        Locker locker2(mapper);
+        IRequestMapper::Settings settings=map_request(lpECB,mapper,site.c_str(),targeturl);
+        pair<bool,const char*> application_id=settings.first->getString("applicationId");
+        application=conf->getApplication(application_id.second);
+        const IPropertySet* sessionProps=application ? application->getPropertySet("Sessions") : NULL;
+        if (!application || !sessionProps)
+            return WriteClientError(lpECB,"Unable to map request to application session settings, check configuration.");
+
+        SHIRE shire(application);
+
+        // Make sure we only process the SHIRE requests.
+        if (!strstr(targeturl.c_str(),shire.getShireURL(targeturl.c_str())))
+            return WriteClientError(lpECB,"The request's application and associated shireURL setting are inconsistent.");;
+
+        pair<bool,const char*> shib_cookie=sessionProps->getString("cookieName");
+        pair<bool,const char*> shib_cookie_props=sessionProps->getString("cookieProps");
+        if (!shib_cookie.first)
+            return WriteClientError(lpECB,"No session cookie name defined for this application, check configuration.");
+
+        ShibMLP markupProcessor(application);
+        markupProcessor.insert("requestURL", targeturl.c_str());
+
+        // Make sure this is SSL, if it should be
+        pair<bool,bool> shireSSL=sessionProps->getBool("shireSSL");
+        if (!shireSSL.first || shireSSL.second) {
             GetServerVariable(lpECB,"HTTPS",buf,10);
             if (buf!="on")
                 throw ShibTargetException(SHIBRPC_OK,"blocked non-SSL access to SHIRE POST processor");
         }
         
-        // Make sure this is a POST
-        if (stricmp(lpECB->lpszMethod,"POST"))
+        // If this is a GET, we manufacture an AuthnRequest.
+        if (!stricmp(lpECB->lpszMethod,"GET")) {
+            const char* areq=lpECB->lpszQueryString ? shire.getLazyAuthnRequest(lpECB->lpszQueryString) : NULL;
+            if (!areq)
+                throw ShibTargetException(SHIBRPC_OK, "malformed arguments to request a new session");
+            targeturl = string("Location: ") + areq + "\r\n"
+                "Expires: 01-Jan-1997 12:00:00 GMT\r\n"
+                "Cache-Control: private,no-store,no-cache\r\n"
+                "Connection: close\r\n";
+            HSE_SEND_HEADER_EX_INFO hinfo;
+            hinfo.pszStatus="302 Moved";
+            hinfo.pszHeader=targeturl.c_str();
+            hinfo.cchStatus=9;
+            hinfo.cchHeader=targeturl.length();
+            hinfo.fKeepConn=FALSE;
+            if (lpECB->ServerSupportFunction(lpECB->ConnID,HSE_REQ_SEND_RESPONSE_HEADER_EX,&hinfo,0,0))
+                return HSE_STATUS_SUCCESS;
+            return HSE_STATUS_ERROR;
+        }
+        else if (stricmp(lpECB->lpszMethod,"POST"))
             throw ShibTargetException(SHIBRPC_OK,"blocked non-POST to SHIRE POST processor");
 
         // Sure sure this POST is an appropriate content type
         if (!lpECB->lpszContentType || stricmp(lpECB->lpszContentType,"application/x-www-form-urlencoded"))
             throw ShibTargetException(SHIBRPC_OK,"blocked bad content-type to SHIRE POST processor");
     
-        // Make sure the "bytes sent" is a reasonable number and that we have all of it.
+        // Read the data.
+        pair<const char*,const char*> elements=pair<const char*,const char*>(NULL,NULL);
         if (lpECB->cbTotalBytes > 1024*1024) // 1MB?
-            throw ShibTargetException (SHIBRPC_OK,"blocked too-large a post to SHIRE POST processor");
-        else if (lpECB->cbTotalBytes>lpECB->cbAvailable)
-            throw ShibTargetException (SHIBRPC_OK,"blocked incomplete post to SHIRE POST processor");
-
-        // Parse the incoming data.
-        HQUERY params=ParseQuery(lpECB);
-        if (!params)
-            throw ShibTargetException (SHIBRPC_OK,"unable to parse form data");
-
-        // Make sure the TARGET parameter exists
-        const char* target = QueryValue(params,"TARGET");
-        if (!target || *target == '\0')
-            throw ShibTargetException(SHIBRPC_OK,"SHIRE POST failed to find TARGET parameter");
+            throw ShibTargetException(SHIBRPC_OK,"blocked too-large a post to SHIRE POST processor");
+        else if (lpECB->cbTotalBytes!=lpECB->cbAvailable) {
+            string cgistr;
+            char buf[8192];
+            DWORD datalen=lpECB->cbTotalBytes;
+            while (datalen) {
+                DWORD buflen=8192;
+                BOOL ret=lpECB->ReadClient(lpECB->ConnID,buf,&buflen);
+                if (!ret || !buflen)
+                    throw ShibTargetException(SHIBRPC_OK,"error reading POST data from browser");
+                cgistr.append(buf,buflen);
+                datalen-=buflen;
+            }
+            elements=shire.getFormSubmission(cgistr.c_str(),cgistr.length());
+        }
+        else
+            elements=shire.getFormSubmission(reinterpret_cast<char*>(lpECB->lpbData),lpECB->cbAvailable);
     
-        // Make sure the SAMLResponse parameter exists
-        const char* post = QueryValue(params,"SAMLResponse");
-        if (!post || *post == '\0')
-            throw ShibTargetException (SHIBRPC_OK,"SHIRE POST failed to find SAMLResponse parameter");
-
+        // Make sure the SAML Response parameter exists
+        if (!elements.first || !*elements.first)
+            throw ShibTargetException(SHIBRPC_OK, "SHIRE POST failed to find SAMLResponse form element");
+    
+        // Make sure the target parameter exists
+        if (!elements.second || !*elements.second)
+            throw ShibTargetException(SHIBRPC_OK, "SHIRE POST failed to find TARGET form element");
+            
         GetServerVariable(lpECB,"REMOTE_ADDR",buf,16);
 
         // Process the post.
         string cookie;
-        RPCError* status = shire.sessionCreate(post,buf,application_id.c_str(),cookie);
+        RPCError* status = shire.sessionCreate(elements.first,buf,cookie);
     
         if (status->isError()) {
             if (status->isRetryable()) {
                 delete status;
-                char timebuf[16];
-                sprintf(timebuf,"%u",time(NULL));
-                string wayf=wayfLocation + "?shire=" + url_encode(shire_url.c_str()) + "&target=" + url_encode(target) +
-                    "&time=" + timebuf + "&providerId=" + application_id;
-                DWORD len=wayf.length();
-                if (lpECB->ServerSupportFunction(lpECB->ConnID,HSE_REQ_SEND_URL_REDIRECT_RESP,(LPVOID)wayf.c_str(),&len,0))
+                const char* loc=shire.getAuthnRequest(elements.second);
+                DWORD len=strlen(loc);
+                if (lpECB->ServerSupportFunction(lpECB->ConnID,HSE_REQ_SEND_URL_REDIRECT_RESP,(LPVOID)loc,&len,0))
                     return HSE_STATUS_SUCCESS;
                 return HSE_STATUS_ERROR;
             }
@@ -904,38 +896,46 @@ extern "C" DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB)
             // Return this error to the user.
             markupProcessor.insert(*status);
             delete status;
-            return WriteClientError(lpECB,shireError.c_str(),markupProcessor);
+            return WriteClientError(lpECB,application,"shire",markupProcessor);
         }
         delete status;
     
         // We've got a good session, set the cookie and redirect to target.
-        shib_cookie = "Set-Cookie: " + shib_cookie + '=' + cookie + "; path=/\r\n" 
-            "Location: " + target + "\r\n"
+        cookie = string("Set-Cookie: ") + shib_cookie.second + '=' + cookie +
+            (shib_cookie_props.first ? shib_cookie_props.second : "; path=/") + "\r\n" 
+            "Location: " + elements.second + "\r\n"
             "Expires: 01-Jan-1997 12:00:00 GMT\r\n"
             "Cache-Control: private,no-store,no-cache\r\n"
             "Connection: close\r\n";
         HSE_SEND_HEADER_EX_INFO hinfo;
         hinfo.pszStatus="302 Moved";
-        hinfo.pszHeader=shib_cookie.c_str();
+        hinfo.pszHeader=cookie.c_str();
         hinfo.cchStatus=9;
-        hinfo.cchHeader=shib_cookie.length();
+        hinfo.cchHeader=cookie.length();
         hinfo.fKeepConn=FALSE;
         if (lpECB->ServerSupportFunction(lpECB->ConnID,HSE_REQ_SEND_RESPONSE_HEADER_EX,&hinfo,0,0))
             return HSE_STATUS_SUCCESS;
     }
     catch (ShibTargetException &e) {
-        markupProcessor.insert ("errorType", "SHIRE Processing Error");
-        markupProcessor.insert ("errorText", e.what());
-        markupProcessor.insert ("errorDesc", "An error occurred while processing your request.");
-        return WriteClientError(lpECB,shireError.c_str(),markupProcessor);
+        if (application) {
+            ShibMLP markupProcessor(application);
+            markupProcessor.insert("errorType", "Session Creation Service Error");
+            markupProcessor.insert("errorText", e.what());
+            markupProcessor.insert("errorDesc", "An error occurred while processing your request.");
+            return WriteClientError(lpECB,application,"shire",markupProcessor);
+        }
     }
+#ifndef _DEBUG
     catch (...) {
-        markupProcessor.insert ("errorType", "SHIRE Processing Error");
-        markupProcessor.insert ("errorText", "Unexpected Exception");
-        markupProcessor.insert ("errorDesc", "An error occurred while processing your request.");
-        return WriteClientError(lpECB,shireError.c_str(),markupProcessor);
+        if (application) {
+            ShibMLP markupProcessor(application);
+            markupProcessor.insert("errorType", "Session Creation Service Error");
+            markupProcessor.insert("errorText", "Unexpected Exception");
+            markupProcessor.insert("errorDesc", "An error occurred while processing your request.");
+            return WriteClientError(lpECB,application,"shire",markupProcessor);
+        }
     }
+#endif
     
     return HSE_STATUS_ERROR;
 }
-