Redesigned target around URL->application mapping
[shibboleth/sp.git] / mod_shire / mod_shire.cpp
index 062a1de..615f1f6 100644 (file)
@@ -6,6 +6,12 @@
  * $Id$
  */
 
+// SAML Runtime
+#include <saml/saml.h>
+#include <shib/shib.h>
+#include <shib/shib-threads.h>
+#include <shib-target/shib-target.h>
+
 // Apache specific header files
 #include "httpd.h"
 #include "http_config.h"
 #include "http_core.h"
 #include "http_log.h"
 
-// SAML Runtime
-#include <saml/saml.h>
-#include <shib/shib.h>
-#include <shib-target/shib-target.h>
-
 #include <fstream>
 #include <sstream>
 #include <stdexcept>
@@ -39,38 +40,8 @@ extern "C" module MODULE_VAR_EXPORT shire_module;
 namespace {
     char* g_szSHIREURL = NULL;
     char* g_szSHIREConfig = NULL;
-    RPCHandle *rpc_handle = NULL;
-    ShibTargetConfig * g_szConfig = NULL;
-}
-
-// per-server configuration structure
-struct shire_server_config
-{
-    char* serverName;          // Name of this server
-};
-
-// creates the per-server configuration
-extern "C" void* create_shire_server_config (pool * p, server_rec * s)
-{
-    shire_server_config* sc=(shire_server_config*)ap_pcalloc(p,sizeof(shire_server_config));
-    return sc;
-}
-
-// overrides server configuration in virtual servers
-extern "C" void* merge_shire_server_config (pool* p, void* base, void* sub)
-{
-    shire_server_config* sc=(shire_server_config*)ap_pcalloc(p,sizeof(shire_server_config));
-    shire_server_config* parent=(shire_server_config*)base;
-    shire_server_config* child=(shire_server_config*)sub;
-
-    if (child->serverName)
-        sc->serverName=ap_pstrdup(p,child->serverName);
-    else if (parent->serverName)
-        sc->serverName=ap_pstrdup(p,parent->serverName);
-    else
-        sc->serverName=NULL;
-
-    return sc;
+    ThreadKey* rpc_handle_key = NULL;
+    ShibTargetConfig* g_Config = NULL;
 }
 
 // per-dir module configuration structure
@@ -113,15 +84,6 @@ extern "C" const char* ap_set_global_string_slot(cmd_parms* parms, void*, const
     return NULL;
 }
 
-// generic per-server slot handlers
-extern "C" const char* ap_set_server_string_slot(cmd_parms* parms, void*, const char* arg)
-{
-    char* base=(char*)ap_get_module_config(parms->server->module_config,&shire_module);
-    int offset=(int)parms->info;
-    *((char**)(base + offset))=ap_pstrdup(parms->pool,arg);
-    return NULL;
-}
-
 // some shortcuts for directory config slots
 extern "C" const char* set_lifetime(cmd_parms* parms, shire_dir_config* dc, const char* arg)
 {
@@ -159,6 +121,12 @@ static command_rec shire_cmds[] = {
   {NULL}
 };
 
+namespace {
+    void destroy_handle(void* data)
+    {
+        delete (RPCHandle*)data;
+    }
+}
 
 /* 
  * shire_child_init()
@@ -171,23 +139,22 @@ extern "C" void shire_child_init(server_rec* s, pool* p)
     ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s,
                 "shire_child_init() starting");
 
-    if (g_szConfig) {
+    if (g_Config) {
       ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,s,
                   "shire_child_init(): already initialized!");
       exit (1);
     }
 
     try {
-      g_szConfig = &(ShibTargetConfig::init(SHIBTARGET_SHIRE, g_szSHIREConfig));
+      g_Config = &(ShibTargetConfig::init(SHIBTARGET_SHIRE, g_szSHIREConfig));
     } catch (...) {
       ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s,
                   "shire_child_init() failed to initialize SHIB Target");
       exit (1);
     }
 
-    // Create the RPC Handle..  Note: this should be per _thread_
-    // if there is some way to do that reasonably..
-    rpc_handle = new RPCHandle(SHIB_SHAR_SOCKET, SHIBRPC_PROG, SHIBRPC_VERS_1);
+    // Create the RPC Handle TLS key.
+    rpc_handle_key=ThreadKey::create(destroy_handle);
 
     ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s,"shire_child_init() done");
 }
@@ -199,9 +166,9 @@ extern "C" void shire_child_init(server_rec* s, pool* p)
  */
 extern "C" void shire_child_exit(server_rec* s, pool* p)
 {
-    delete rpc_handle;
-    g_szConfig->shutdown();
-    g_szConfig = NULL;
+    delete rpc_handle_key;
+    g_Config->shutdown();
+    g_Config = NULL;
     ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s,"shire_child_exit() done");
 }
 
@@ -231,85 +198,35 @@ static char* url_encode(request_rec* r, const char* s)
     return ret;
 }
 
-// Return the "name" of this server to look up configuration options
-static const char* get_service_name(request_rec* r)
+static const char* get_application_id(request_rec* r)
 {
-  shire_server_config* sc =
-    (shire_server_config*) ap_get_module_config(r->server->module_config,
-                                               &shire_module);
-
-  if (sc->serverName)
-    return sc->serverName;
-
-  return ap_get_server_name(r);
-}
-
-// return the "normalized" target URL
-static const char* get_target(request_rec* r, const char* target)
-{
-  const char* serverName = get_service_name(r);
-  string tag;
-  if ((g_szConfig->getINI()).get_tag (serverName, "normalizeRequest", true, &tag))
-  {
-    if (ShibINI::boolean (tag))
-    {
-        const char* colon=strchr(target,':');
-        const char* slash=strchr(colon+3,'/');
-        const char* second_colon=strchr(colon+3,':');
-        return ap_pstrcat(r->pool,ap_pstrndup(r->pool,target,colon+3-target),
-                         ap_get_server_name(r),
-                         (second_colon && second_colon < slash) ?
-                         second_colon : slash,
-                         NULL);
-    }
-  }
-  return target;
+    ApplicationMapper mapper;
+    return ap_pstrdup(r->pool,
+        mapper->getApplicationFromParsedURL(
+            ap_http_method(r), ap_get_server_name(r), ap_get_server_port(r), r->unparsed_uri
+            )
+       );
 }
 
-static const char* get_shire_location(request_rec* r, const char* target, bool encode)
+static const char* get_shire_location(request_rec* r, const char* target, const char* application_id)
 {
-  ShibINI& ini = g_szConfig->getINI();
-  const char* serverName = get_service_name(r);
   string shire_location;
+  ShibINI& ini = g_Config->getINI();
 
-  if (g_szSHIREURL)
-    shire_location = g_szSHIREURL;
-  else if (! ini.get_tag (serverName, "shireURL", true, &shire_location)) {
+  if (!ini.get_tag (application_id, "shireURL", true, &shire_location)) {
     ap_log_rerror(APLOG_MARK,APLOG_ERR,r,
-                 "shire_get_location() no shireURL configuration for %s",
-                 serverName);
+                 "shire_get_location() no shireURL configuration for %s", application_id);
     return NULL;
   }
 
   const char* shire = shire_location.c_str();
 
-  if (*shire != '/') {
-    if (encode)
-      return url_encode(r,shire);
-    else
+  if (*shire != '/')
       return ap_pstrdup(r->pool,shire);
-    }    
-    const char* colon=strchr(target,':');
-    const char* slash=strchr(colon+3,'/');
-    if (encode)
-      return url_encode(r,ap_pstrcat(r->pool,
-                                    ap_pstrndup(r->pool,target,slash-target),
-                                    shire,NULL));
-    else
-      return ap_pstrcat(r->pool, ap_pstrndup(r->pool,target,slash-target),
-                       shire, NULL);
-}
-
-static bool is_shire_location(request_rec* r, const char* target)
-{
-  const char* shire = get_shire_location(r, target, false);
-
-  if (!shire) return false;
-
-  if (!strstr(target, shire))
-    return false;
 
-  return (!strcmp(target,shire));
+  const char* colon=strchr(target,':');
+  const char* slash=strchr(colon+3,'/');
+  return ap_pstrcat(r->pool, ap_pstrndup(r->pool,target,slash-target), shire, NULL);
 }
 
 static int shire_error_page(request_rec* r, const char* filename, ShibMLP& mlp)
@@ -330,173 +247,187 @@ static int shire_error_page(request_rec* r, const char* filename, ShibMLP& mlp)
 
 extern "C" int shire_check_user(request_rec* r)
 {
+    ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_user: ENTER");
+    shire_dir_config* dc=(shire_dir_config*)ap_get_module_config(r->per_dir_config,&shire_module);
+
+    // This will always be normalized, because Apache uses ap_get_server_name in this API call.
+    const char* targeturl=ap_construct_url(r->pool,r->unparsed_uri,r);
+    
+    // Map request to application ID, which is the key for config lookup.
+    const char* application_id=get_application_id(r);
+    
+    // Get unescaped location of this application's assertion consumer service.
+    const char* unescaped_shire = get_shire_location(r, targeturl, application_id);
+    
+    if (strstr(targeturl,unescaped_shire)) {
+      ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
+           "shire_check_user: REQUEST FOR SHIRE!  Maybe you did not configure the SHIRE Handler?");
+      return SERVER_ERROR;
+    }
+    else {
+      // Regular access to arbitrary resource...check AuthType
+      const char *auth_type=ap_auth_type (r);
+      if (!auth_type)
+        return DECLINED;
+
+      if (strcasecmp(auth_type,"shibboleth"))
+      {
+        if (!strcasecmp(auth_type,"basic") && dc->bBasicHijack==1)
+        {
+            core_dir_config* conf=
+                (core_dir_config*)ap_get_module_config(r->per_dir_config,
+                    ap_find_linked_module("http_core.c"));
+            conf->ap_auth_type="shibboleth";
+        }
+        else
+            return DECLINED;
+      }
+
+      // set the connection authtype
+      if (r->connection)
+        r->connection->ap_auth_type = "shibboleth";
+
+      // SSL check.
+      if (dc->bSSLOnly==1 && strcmp(ap_http_method(r),"https"))
+      {
+        ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"shire_check_user() blocked non-SSL access");
+        return SERVER_ERROR;
+      }
+    }
+
     ostringstream threadid;
     threadid << "[" << getpid() << "] shire" << '\0';
     saml::NDC ndc(threadid.str().c_str());
 
-    ShibINI& ini = g_szConfig->getINI();
-    ShibMLP markupProcessor;
+    ShibINI& ini = g_Config->getINI();
 
     ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
-                 "shire_check_user: ENTER");
-
-    shire_dir_config* dc=
-        (shire_dir_config*)ap_get_module_config(r->per_dir_config,&shire_module);
-
-    const char* targeturl=get_target(r,ap_construct_url(r->pool,r->unparsed_uri,r));
-    const char * shire_location = get_shire_location(r,targeturl,true);
-    if (!shire_location) return SERVER_ERROR;
-    string shire_url = get_shire_location(r,targeturl,false);
+                    "shire_check_user() Shib check for %s", targeturl);
 
-    const char* serverName = get_service_name (r);
+    
     string tag;
-    bool has_tag = ini.get_tag (serverName, "checkIPAddress", true, &tag);
+    bool has_tag = ini.get_tag (application_id, "checkIPAddress", true, &tag);
     dc->config.checkIPAddress = (has_tag ? ShibINI::boolean (tag) : false);
 
     string shib_cookie;
-    if (! ini.get_tag (serverName, "cookieName", true, &shib_cookie)) {
+    if (!ini.get_tag(application_id, "cookieName", true, &shib_cookie)) {
       ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
-                   "shire_check_user: no cookieName configuration for %s",
-                   serverName);
+                   "shire_check_user: no cookieName configuration for %s", application_id);
       return SERVER_ERROR;
     }
 
     string wayfLocation;
-    if (! ini.get_tag (serverName, "wayfURL", true, &wayfLocation)) {
+    if (!ini.get_tag(application_id, "wayfURL", true, &wayfLocation)) {
       ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
-                   "shire_check_user: no wayfURL configuration for %s",
-                   serverName);
+                   "shire_check_user: no wayfURL configuration for %s", application_id);
       return SERVER_ERROR;
     }
 
     string shireError;
-    if (! ini.get_tag (serverName, "shireError", true, &shireError)) {
+    if (!ini.get_tag(application_id, "shireError", true, &shireError)) {
       ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
-                   "shire_check_user: no shireError configuration for %s",
-                   serverName);
+                   "shire_check_user: no shireError configuration for %s", application_id);
       return SERVER_ERROR;
     }
+    
+    // Get an RPC handle and build the SHIRE object.
+    RPCHandle* rpc_handle = (RPCHandle*)rpc_handle_key->getData();
+    if (!rpc_handle)
+    {
+        rpc_handle = new RPCHandle(shib_target_sockname(), SHIBRPC_PROG, SHIBRPC_VERS_1);
+        rpc_handle_key->setData(rpc_handle);
+    }
+    SHIRE shire(rpc_handle, dc->config, unescaped_shire);
 
-    ini.get_tag (serverName, "supportContact", true, &tag);
-    markupProcessor.insert ("supportContact", has_tag ? tag : "");
-    has_tag = ini.get_tag (serverName, "logoLocation", true, &tag);
-    markupProcessor.insert ("logoLocation", has_tag ? tag : "");
-    markupProcessor.insert ("requestURL", targeturl);
-
-    SHIRE shire(rpc_handle, dc->config, shire_url);
-
-    if (is_shire_location (r, targeturl)) {
-      ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
-                   "shire_check_user: REQUEST FOR SHIRE!  Maybe you did not configure the SHIRE Handler?");
-      return SERVER_ERROR;
-
-    } else {
-      // Regular access to arbitrary resource...check AuthType
-
-      const char *auth_type=ap_auth_type (r);
-      if (!auth_type)
-        return DECLINED;
-
-      if (strcasecmp(auth_type,"shibboleth"))
-      {
-        if (!strcasecmp(auth_type,"basic") && dc->bBasicHijack==1)
-       {
-         core_dir_config* conf=
-           (core_dir_config*)ap_get_module_config(r->per_dir_config,
-                                                  ap_find_linked_module("http_core.c"));
-         conf->ap_auth_type="shibboleth";
-       }
-       else
-         return DECLINED;
-      }
-
-      // set the connection authtype
-      if (r->connection) r->connection->ap_auth_type = "shibboleth";
-
-      ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
-                   "shire_check_user() Shib check for %s", targeturl);
-
-      // SSL check.
-      if (dc->bSSLOnly==1 && strcmp(ap_http_method(r),"https"))
-      {
-        ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,
-                     "shire_check_user() blocked non-SSL access");
-        return SERVER_ERROR;
-      }
-
-      // We're in charge, so check for cookie.
-      const char* session_id=NULL;
-      const char* cookies=ap_table_get(r->headers_in,"Cookie");
+    // We're in charge, so check for cookie.
+    const char* session_id=NULL;
+    const char* cookies=ap_table_get(r->headers_in,"Cookie");
 
-      if (cookies)
+    if (cookies)
+    {
         ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
-                     "shire_check_user() cookies found: %s",
-                     cookies);               
+                        "shire_check_user() cookies found: %s",cookies);
+        if (session_id=strstr(cookies,shib_cookie.c_str()))
+        {
+            // Yep, we found a cookie -- pull it out (our session_id)
+            session_id+=strlen(shib_cookie.c_str()) + 1; /* Skip over the '=' */
+            char* cookiebuf = ap_pstrdup(r->pool,session_id);
+            char* cookieend = strchr(cookiebuf,';');
+            if (cookieend)
+                *cookieend = '\0';    /* Ignore anyting after a ; */
+            session_id=cookiebuf;
+        }
+    }
 
-      if (!cookies || !(session_id=strstr(cookies,shib_cookie.c_str())))
-      {
-        // No cookie.  Redirect to WAYF.
+    if (!session_id || !*session_id)
+    {
+        // No acceptable cookie.  Redirect to WAYF.
         ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
                      "shire_check_user() no cookie found -- redirecting to WAYF");
         char* wayf=ap_pstrcat(r->pool,wayfLocation.c_str(),
-                             "?shire=",shire_location,
+                             "?shire=",url_encode(r,unescaped_shire),
                              "&target=",url_encode(r,targeturl),NULL);
-       ap_table_setn(r->headers_out,"Location",wayf);
-       return REDIRECT;
-      }
-
-      // Yep, we found a cookie -- pull it out (our session_id)
-      session_id+=strlen(shib_cookie.c_str()) + 1;     /* Skip over the '=' */
-      char* cookiebuf = ap_pstrdup(r->pool,session_id);
-      char* cookieend = strchr(cookiebuf,';');
-      if (cookieend)
-       *cookieend = '\0';      /* Ignore anyting after a ; */
-      session_id=cookiebuf;
-
-      // Make sure this session is still valid
-      RPCError* status = NULL;
-
-      try {
-       status = shire.sessionIsValid(session_id, r->connection->remote_ip,
-                                     targeturl);
+        ap_table_setn(r->headers_out,"Location",wayf);
+        return REDIRECT;
+    }
 
-      } catch (ShibTargetException &e) {
-       ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
-                     "shire_check_user(): %s", e.what());
-       
-       markupProcessor.insert ("errorType", "SHIRE Processing Error");
-       markupProcessor.insert ("errorText", e.what());
-       markupProcessor.insert ("errorDesc", "An error occurred while processing your request.");
-       return shire_error_page (r, shireError.c_str(), markupProcessor);
-      }
+    // Make sure this session is still valid
+    RPCError* status = NULL;
+    ShibMLP markupProcessor;
+    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", targeturl);
 
-      // Check the status
-      if (status->isError()) {
+    try {
+        status = shire.sessionIsValid(session_id, r->connection->remote_ip,application_id);
+    }
+    catch (ShibTargetException &e) {
+        ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_user(): %s", e.what());
+        markupProcessor.insert ("errorType", "SHIRE Processing Error");
+        markupProcessor.insert ("errorText", e.what());
+        markupProcessor.insert ("errorDesc", "An error occurred while processing your request.");
+        return shire_error_page (r, shireError.c_str(), markupProcessor);
+    }
+    catch (...) {
+        ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_user(): caught unexpected error");
+        markupProcessor.insert ("errorType", "SHIRE Processing Error");
+        markupProcessor.insert ("errorText", "Unexpected Exception");
+        markupProcessor.insert ("errorDesc", "An error occurred while processing your request.");
+        return shire_error_page (r, shireError.c_str(), markupProcessor);
+    }
 
-       ap_log_rerror(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,r,
+    // Check the status
+    if (status->isError()) {
+        ap_log_rerror(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,r,
                      "shire_check_user() session invalid: %s",
-                     status->error_msg.c_str());
-
-        // Oops, session is invalid.  Redirect to WAYF.
-        char* wayf=ap_pstrcat(r->pool,wayfLocation.c_str(),
-                             "?shire=",shire_location,
-                             "&target=",url_encode(r,targeturl),NULL);
-       ap_table_setn(r->headers_out,"Location",wayf);
-
-       delete status;
-       return REDIRECT;
-
-      } else {
-       delete status;
-        ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
-                     "shire_check_user() success");
-       return OK;
-      }
+                     status->getText());
+
+        if (status->isRetryable()) {
+            // Oops, session is invalid.  Redirect to WAYF.
+            char* wayf=ap_pstrcat(r->pool,wayfLocation.c_str(),
+                               "?shire=",url_encode(r,unescaped_shire),
+                               "&target=",url_encode(r,targeturl),NULL);
+            ap_table_setn(r->headers_out,"Location",wayf);
+
+            delete status;
+            return REDIRECT;
+        }
+        else {
+            // return the error page to the user
+            markupProcessor.insert (*status);
+            delete status;
+            return shire_error_page (r, shireError.c_str(), markupProcessor);
+        }
+    }
+    else {
+        delete status;
+        ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_user() success");
+        return OK;
     }
 
-    ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,
-                 "shire_check_user() server error");
+    ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"shire_check_user() server error");
     return SERVER_ERROR;
 }
 
@@ -506,55 +437,60 @@ extern "C" int shire_post_handler (request_rec* r)
   threadid << "[" << getpid() << "] shire" << '\0';
   saml::NDC ndc(threadid.str().c_str());
 
-  ShibINI& ini = g_szConfig->getINI();
+  ShibINI& ini = g_Config->getINI();
   ShibMLP markupProcessor;
 
-  ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
-               "shire_post_handler() ENTER");
+  ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_post_handler() ENTER");
 
-  const char* targeturl=get_target(r,ap_construct_url(r->pool,r->unparsed_uri,r));
-  const char * shire_location = get_shire_location(r,targeturl,true);
-  if (!shire_location) return SERVER_ERROR;
-  string shire_url = get_shire_location(r,targeturl,false);
+  // This will always be normalized, because Apache uses ap_get_server_name in this API call.
+  const char* targeturl = ap_construct_url(r->pool,r->unparsed_uri,r);
+   
+  // Map request to application ID, which is the key for config lookup.
+  const char* application_id = get_application_id(r);
+    
+  // The SHIRE URL is the current request URL, by definition...
+  const char* unescaped_shire = targeturl;
 
-  const char* serverName = get_service_name (r);
   string tag;
-  bool has_tag = ini.get_tag (serverName, "checkIPAddress", true, &tag);
+  bool has_tag = ini.get_tag(application_id, "checkIPAddress", true, &tag);
   SHIREConfig config;
-  config.checkIPAddress = (has_tag ? ShibINI::boolean (tag) : false);
+  config.checkIPAddress = (has_tag ? ShibINI::boolean(tag) : false);
 
   string shib_cookie;
-  if (! ini.get_tag (serverName, "cookieName", true, &shib_cookie)) {
+  if (! ini.get_tag(application_id, "cookieName", true, &shib_cookie)) {
     ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
-                 "shire_check_user: no cookieName configuration for %s",
-                 serverName);
+                 "shire_check_user: no cookieName configuration for %s", application_id);
     return SERVER_ERROR;
   }
 
   string wayfLocation;
-  if (! ini.get_tag (serverName, "wayfURL", true, &wayfLocation)) {
+  if (! ini.get_tag(application_id, "wayfURL", true, &wayfLocation)) {
     ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
-                 "shire_check_user: no wayfURL configuration for %s",
-                 serverName);
+                 "shire_check_user: no wayfURL configuration for %s", application_id);
     return SERVER_ERROR;
   }
 
   string shireError;
-  if (! ini.get_tag (serverName, "shireError", true, &shireError)) {
+  if (! ini.get_tag(application_id, "shireError", true, &shireError)) {
     ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
-                 "shire_check_user: no shireError configuration for %s",
-                 serverName);
+                 "shire_check_user: no shireError configuration for %s", application_id);
     return SERVER_ERROR;
   }
 
-  ini.get_tag (serverName, "supportContact", true, &tag);
-  markupProcessor.insert ("supportContact", has_tag ? tag : "");
-  has_tag = ini.get_tag (serverName, "logoLocation", true, &tag);
-  markupProcessor.insert ("logoLocation", has_tag ? tag : "");
-  markupProcessor.insert ("requestURL", targeturl);
+  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", targeturl);
   
-  SHIRE shire(rpc_handle, config, shire_url);
+    // Get an RPC handle and build the SHIRE object.
+    RPCHandle* rpc_handle = (RPCHandle*)rpc_handle_key->getData();
+    if (!rpc_handle)
+    {
+        rpc_handle = new RPCHandle(shib_target_sockname(), SHIBRPC_PROG, SHIBRPC_VERS_1);
+        rpc_handle_key->setData(rpc_handle);
+    }
+    SHIRE shire(rpc_handle, config, unescaped_shire);
 
   // Process SHIRE POST
 
@@ -563,19 +499,17 @@ extern "C" int shire_post_handler (request_rec* r)
       
   try {
     string sslonly;
-    if (! ini.get_tag (serverName, "shireSSLOnly", true, &sslonly))
+    if (!ini.get_tag(application_id, "shireSSLOnly", true, &sslonly))
       ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
                    "shire_post_handler: no shireSSLOnly configuration");
     
     // Make sure this is SSL, if it should be
     if (ShibINI::boolean(sslonly) && strcmp(ap_http_method(r),"https"))
-      throw ShibTargetException (SHIBRPC_OK,
-                                "blocked non-SSL access to SHIRE POST processor");
+      throw ShibTargetException(SHIBRPC_OK, "blocked non-SSL access to SHIRE POST processor");
 
     // Make sure this is a POST
     if (strcasecmp (r->method, "POST"))
-      throw ShibTargetException (SHIBRPC_OK,
-                                "blocked non-POST to SHIRE POST processor");
+      throw ShibTargetException(SHIBRPC_OK, "blocked non-POST to SHIRE POST processor");
 
     // Sure sure this POST is an appropriate content type
     const char *ct = ap_table_get (r->headers_in, "Content-type");
@@ -618,24 +552,24 @@ extern "C" int shire_post_handler (request_rec* r)
 
     // process the post
     string cookie;
-    RPCError* status = shire.sessionCreate(post, r->connection->remote_ip, cookie);
+    RPCError* status = shire.sessionCreate(post, r->connection->remote_ip, application_id, cookie);
 
     if (status->isError()) {
       ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,
                    "shire_post_handler() POST process failed (%d): %s",
-                   status->status, status->error_msg.c_str());
+                   status->getCode(), status->getText());
 
-      if (status->isRetryable()) {
-       ap_log_rerror(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,r,
-                     "shire_post_handler() Retrying POST by redirecting to WAYF");
+    if (status->isRetryable()) {
+         ap_log_rerror(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,r,
+               "shire_post_handler() Retrying POST by redirecting to WAYF");
        
-       char* wayf=ap_pstrcat(r->pool,wayfLocation.c_str(),
-                             "?shire=",shire_location,
+        char* wayf=ap_pstrcat(r->pool,wayfLocation.c_str(),
+                             "?shire=",url_encode(r,unescaped_shire),
                              "&target=",url_encode(r,target),NULL);
-       ap_table_setn(r->headers_out,"Location",wayf);
-       delete status;
-       return REDIRECT;
-      }
+        ap_table_setn(r->headers_out,"Location",wayf);
+        delete status;
+        return REDIRECT;
+    }
 
       // return this error to the user.
       markupProcessor.insert (*status);
@@ -674,9 +608,16 @@ extern "C" int shire_post_handler (request_rec* r)
     markupProcessor.insert ("errorDesc", "An error occurred while processing your request.");
     return shire_error_page (r, shireError.c_str(), markupProcessor);
   }
+  catch (...) {
+    ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_post_handler(): unexpected exception");
+  
+    markupProcessor.insert ("errorType", "SHIRE Processing Error");
+    markupProcessor.insert ("errorText", "Unexpected Exception");
+    markupProcessor.insert ("errorDesc", "An error occurred while processing your request.");
+    return shire_error_page (r, shireError.c_str(), markupProcessor);
+  }
 
-  ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,
-               "shire_post_handler() server error");
+  ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"shire_post_handler() server error");
   return SERVER_ERROR;
 }
 
@@ -696,8 +637,8 @@ module MODULE_VAR_EXPORT shire_module = {
     mod_shire_init,            /* initializer */
     create_shire_dir_config,   /* dir config creater */
     merge_shire_dir_config,    /* dir merger --- default is to override */
-    create_shire_server_config,        /* server config */
-    merge_shire_server_config, /* merge server config */
+    NULL,                      /* server config */
+    NULL,                      /* merge server config */
     shire_cmds,                        /* command table */
     shire_handlers,            /* handlers */
     NULL,                      /* filename translation */