New endpoint management and refactored profile methods.
authorcantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Wed, 6 Apr 2005 01:45:14 +0000 (01:45 +0000)
committercantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Wed, 6 Apr 2005 01:45:14 +0000 (01:45 +0000)
git-svn-id: https://svn.middleware.georgetown.edu/cpp-sp/trunk@1504 cb58f699-b61c-0410-a6fe-9272a202ed29

apache/mod_apache.cpp
isapi_shib/isapi_shib.cpp
shib-target/XML.cpp
shib-target/internal.h
shib-target/shib-config.cpp
shib-target/shib-ini.cpp
shib-target/shib-target.cpp
shib-target/shib-target.h

index 4f628fd..bc0ce10 100644 (file)
@@ -412,8 +412,7 @@ public:
 
 extern "C" int shib_check_user(request_rec* r)
 {
-  ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r),
-               "shib_check_user(%d): ENTER\n", (int)getpid());
+  ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r), "shib_check_user(%d): ENTER\n", (int)getpid());
 
   ostringstream threadid;
   threadid << "[" << getpid() << "] shib_check_user" << '\0';
@@ -424,7 +423,7 @@ extern "C" int shib_check_user(request_rec* r)
 #endif
     ShibTargetApache sta(r);
 
-    // Check user authentication, the set the post handler bypass
+    // Check user authentication, the set the handler bypass
     pair<bool,void*> res = sta.doCheckAuthN((sta.m_dc->bRequireSession == 1), true);
     apr_pool_userdata_setn((const void*)42,g_UserDataKey,NULL,r->pool);
     if (res.first) return (int)res.second;
@@ -438,50 +437,46 @@ extern "C" int shib_check_user(request_rec* r)
 
 #ifndef _DEBUG
   } catch (...) {
-    ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, SH_AP_R(r),
-                 "shib_check_user threw an uncaught exception!");
+    ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, SH_AP_R(r), "shib_check_user threw an uncaught exception!");
     return SERVER_ERROR;
   }
 #endif
 }
 
-extern "C" int shib_post_handler(request_rec* r)
+extern "C" int shib_handler(request_rec* r)
 {
   ostringstream threadid;
-  threadid << "[" << getpid() << "] shib_post_handler" << '\0';
+  threadid << "[" << getpid() << "] shib_handler" << '\0';
   saml::NDC ndc(threadid.str().c_str());
 
 #ifndef SHIB_APACHE_13
   // With 2.x, this handler always runs, though last.
-  // We check if shib_check_user ran, because it will detect a SHIRE request
+  // We check if shib_check_user ran, because it will detect a handler request
   // and dispatch it directly.
   void* data;
   apr_pool_userdata_get(&data,g_UserDataKey,r->pool);
   if (data==(const void*)42) {
-    ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r),"shib_post_handler skipped since check_user ran");
+    ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r),"shib_handler skipped since check_user ran");
     return DECLINED;
   }
 #endif
 
-  ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r),
-               "shib_post_handler(%d): ENTER", (int)getpid());
+  ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r),"shib_handler(%d): ENTER", (int)getpid());
 
 #ifndef _DEBUG
   try {
 #endif
     ShibTargetApache sta(r);
 
-    pair<bool,void*> res = sta.doHandleProfile();
+    pair<bool,void*> res = sta.doHandler();
     if (res.first) return (int)res.second;
 
-    ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, SH_AP_R(r),
-                 "doHandleProfile() did not do anything.");
+    ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, SH_AP_R(r), "doHandler() did not do anything.");
     return SERVER_ERROR;
 
 #ifndef _DEBUG
   } catch (...) {
-    ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, SH_AP_R(r),
-                 "shib_post_handler threw an uncaught exception!");
+    ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, SH_AP_R(r), "shib_handler threw an uncaught exception!");
     return SERVER_ERROR;
   }
 #endif
@@ -493,8 +488,7 @@ extern "C" int shib_post_handler(request_rec* r)
  */
 extern "C" int shib_auth_checker(request_rec* r)
 {
-  ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r),
-               "shib_auth_checker(%d): ENTER", (int)getpid());
+  ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r), "shib_auth_checker(%d): ENTER", (int)getpid());
 
   ostringstream threadid;
   threadid << "[" << getpid() << "] shib_auth_checker" << '\0';
@@ -513,8 +507,7 @@ extern "C" int shib_auth_checker(request_rec* r)
 
 #ifndef _DEBUG
   } catch (...) {
-    ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, SH_AP_R(r),
-                 "shib_auth_checker threw an uncaught exception!");
+    ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, SH_AP_R(r), "shib_auth_checker threw an uncaught exception!");
     return SERVER_ERROR;
   }
 #endif
@@ -1333,6 +1326,10 @@ extern "C" int shib_auth_checker(request_rec* r)
  */
 extern "C" apr_status_t shib_exit(void* data)
 {
+    if (g_Config) {
+        g_Config->shutdown();
+        g_Config = NULL;
+    }
     ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,NULL,"shib_exit() done\n");
     return OK;
 }
@@ -1447,7 +1444,7 @@ static command_rec shire_cmds[] = {
 
 extern "C"{
 handler_rec shib_handlers[] = {
-  { "shib-shire-post", shib_post_handler },
+  { "shib-handler", shib_handler },
   { NULL }
 };
 
@@ -1480,7 +1477,7 @@ extern "C" void shib_register_hooks (apr_pool_t *p)
   ap_hook_child_init(shib_child_init, NULL, NULL, APR_HOOK_MIDDLE);
   ap_hook_check_user_id(shib_check_user, NULL, NULL, APR_HOOK_MIDDLE);
   ap_hook_auth_checker(shib_auth_checker, NULL, NULL, APR_HOOK_FIRST);
-  ap_hook_handler(shib_post_handler, NULL, NULL, APR_HOOK_LAST);
+  ap_hook_handler(shib_handler, NULL, NULL, APR_HOOK_LAST);
 }
 
 // SHIB Module commands
index 075300a..1881ff8 100644 (file)
@@ -328,7 +328,7 @@ void GetServerVariable(LPEXTENSION_CONTROL_BLOCK lpECB, LPSTR lpszVariable, dyna
     s.erase();
     size=s.size();
 
-    while (lpECB->GetServerVariable(lpECB->ConnID,lpszVariable,s,&size))
+    while (!lpECB->GetServerVariable(lpECB->ConnID,lpszVariable,s,&size))
     {
         // Grumble. Check the error.
         DWORD e=GetLastError();
@@ -402,7 +402,6 @@ public:
     dynabuf remote_addr(16),method(5),content_type(32),hostname(32);
     GetServerVariable(pfc,"SERVER_NAME",hostname,32);
     GetServerVariable(pfc,"REMOTE_ADDR",remote_addr,16);
-    // The last two appear to be unavailable to this filter hook, but we don't need them.
     GetServerVariable(pfc,"REQUEST_METHOD",method,5,false);
     GetServerVariable(pfc,"CONTENT_TYPE",content_type,32,false);
 
@@ -1053,7 +1052,7 @@ class ShibTargetIsapiE : public ShibTarget
   
 public:
   ShibTargetIsapiE(LPEXTENSION_CONTROL_BLOCK lpECB, const site_t& site)
-    : m_log(&Category::getInstance("isapi_shib"))
+    : m_log(&Category::getInstance("isapi_shib_filter"))
   {
     dynabuf ssl(5);
     GetServerVariable(lpECB,"HTTPS",ssl,5);
@@ -1092,7 +1091,42 @@ public:
     if (site.m_name!=host && site.m_aliases.find(host)==site.m_aliases.end())
         host=site.m_name.c_str();
 
-    init(g_Config, scheme, host, atoi(port), url, lpECB->lpszContentType, remote_addr, lpECB->lpszMethod);
+    /*
+     * IIS screws us over on PATH_INFO (the hits keep on coming). We need to figure out if
+     * the server is set up for proper PATH_INFO handling, or "IIS sucks rabid weasels mode",
+     * which is the default. No perfect way to tell, but we can take a good guess by checking
+     * whether the URL is a substring of the PATH_INFO:
+     * 
+     * e.g. for /Shibboleth.sso/SAML/POST
+     * 
+     *  Bad mode (default):
+     *      URL:        /Shibboleth.sso
+     *      PathInfo:   /Shibboleth.sso/SAML/POST
+     * 
+     *  Good mode:
+     *      URL:        /Shibboleth.sso
+     *      PathInfo:   /SAML/POST
+     */
+    
+    string fullurl;
+    
+    // Clearly we're only in bad mode if path info exists at all.
+    if (lpECB->lpszPathInfo && *(lpECB->lpszPathInfo)) {
+        if (strstr(lpECB->lpszPathInfo,url))
+            // Pretty good chance we're in bad mode, unless the PathInfo repeats the path itself.
+            fullurl=lpECB->lpszPathInfo;
+        else {
+            fullurl+=url;
+            fullurl+=lpECB->lpszPathInfo;
+        }
+    }
+    
+    // For consistency with Apache, let's add the query string.
+    if (lpECB->lpszQueryString && *(lpECB->lpszQueryString)) {
+        fullurl+='?';
+        fullurl+=lpECB->lpszQueryString;
+    }
+    init(g_Config, scheme, host, atoi(port), fullurl.c_str(), lpECB->lpszContentType, remote_addr, lpECB->lpszMethod);
 
     m_lpECB = lpECB;
   }
@@ -1128,12 +1162,12 @@ public:
       char buf[8192];
       DWORD datalen=m_lpECB->cbTotalBytes;
       while (datalen) {
-       DWORD buflen=8192;
-       BOOL ret = m_lpECB->ReadClient(m_lpECB->ConnID, buf, &buflen);
-       if (!ret || !buflen)
-         throw FatalProfileException("Error reading profile submission from browser.");
-       cgistr.append(buf, buflen);
-       datalen-=buflen;
+        DWORD buflen=8192;
+        BOOL ret = m_lpECB->ReadClient(m_lpECB->ConnID, buf, &buflen);
+        if (!ret || !buflen)
+          throw FatalProfileException("Error reading profile submission from browser.");
+        cgistr.append(buf, buflen);
+        datalen-=buflen;
       }
       return cgistr;
     }
@@ -1179,7 +1213,7 @@ public:
   // Note that it can also happen with HTAccess, but we don't support that, yet.
   virtual void* returnDecline(void) {
     return (void*)
-      WriteClientError(m_lpECB, "ISAPA extension can only be invoked to process incoming sessions."
+      WriteClientError(m_lpECB, "ISAPI extension can only be invoked to process Shibboleth protocol requests."
                       "Make sure the mapped file extension doesn't match actual content.");
   }
   virtual void* returnOK(void) { return (void*) HSE_STATUS_SUCCESS; }
@@ -1198,7 +1232,7 @@ extern "C" DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB)
     const IApplication* application=NULL;
     try {
         ostringstream threadid;
-        threadid << "[" << getpid() << "] shire_handler" << '\0';
+        threadid << "[" << getpid() << "] isapi_shib_extension" << '\0';
         saml::NDC ndc(threadid.str().c_str());
 
         // Determine web site number. This can't really fail, I don't think.
@@ -1211,7 +1245,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,void*> res = ste.doHandleProfile();
+        pair<bool,void*> res = ste.doHandler();
         if (res.first) return (DWORD)res.second;
         
         return WriteClientError(lpECB, "Shibboleth Extension failed to process request");
index 9e1944c..9836bf5 100644 (file)
@@ -135,6 +135,12 @@ const XMLCh XML::Literals::Application[] =
 const XMLCh XML::Literals::Applications[] =
 { chLatin_A, chLatin_p, chLatin_p, chLatin_l, chLatin_i, chLatin_c, chLatin_a, chLatin_t, chLatin_i, chLatin_o, chLatin_n, chLatin_s, chNull };
 
+const XMLCh XML::Literals::AssertionConsumerService[] =
+{ chLatin_A, chLatin_s, chLatin_s, chLatin_e, chLatin_r, chLatin_t, chLatin_i, chLatin_o, chLatin_n,
+  chLatin_C, chLatin_o, chLatin_n, chLatin_s, chLatin_u, chLatin_m, chLatin_e, chLatin_r,
+  chLatin_S, chLatin_e, chLatin_r, chLatin_v, chLatin_i, chLatin_c, chLatin_e, chNull
+};
+
 const XMLCh XML::Literals::CredentialsProvider[] =
 { chLatin_C, chLatin_r, chLatin_e, chLatin_d, chLatin_e, chLatin_n, chLatin_t, chLatin_i, chLatin_a, chLatin_l, chLatin_s,
   chLatin_P, chLatin_r, chLatin_o, chLatin_v, chLatin_i, chLatin_d, chLatin_e, chLatin_r, chNull
@@ -166,6 +172,12 @@ const XMLCh XML::Literals::htaccess[]=
 const XMLCh XML::Literals::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 };
 
+const XMLCh XML::Literals::index[] =
+{ chLatin_i, chLatin_n, chLatin_d, chLatin_e, chLatin_x, chNull };
+
+const XMLCh XML::Literals::isDefault[] =
+{ chLatin_i, chLatin_s, chLatin_D, chLatin_e, chLatin_f, chLatin_a, chLatin_u, chLatin_l, chLatin_t, chNull };
+
 const XMLCh XML::Literals::Library[] =
 { chLatin_L, chLatin_i, chLatin_b, chLatin_r, chLatin_a, chLatin_r, chLatin_y, chNull };
 
@@ -228,6 +240,11 @@ const XMLCh XML::Literals::SessionCache[] =
   chLatin_C, chLatin_a, chLatin_c, chLatin_h, chLatin_e, chNull
 };
 
+const XMLCh XML::Literals::SessionInitiator[] =
+{ chLatin_S, chLatin_e, chLatin_s, chLatin_s, chLatin_i, chLatin_o, chLatin_n,
+  chLatin_I, chLatin_n, chLatin_i, chLatin_t, chLatin_i, chLatin_a, chLatin_t, chLatin_o, chLatin_r, chNull
+};
+
 const XMLCh XML::Literals::SHAR[]= { chLatin_S, chLatin_H, chLatin_A, chLatin_R, chNull };
 
 const XMLCh XML::Literals::ShibbolethTargetConfig[] =
@@ -240,6 +257,12 @@ const XMLCh XML::Literals::SHIRE[]= { chLatin_S, chLatin_H, chLatin_I, chLatin_R
 
 const XMLCh XML::Literals::Signing[] = { chLatin_S, chLatin_i, chLatin_g, chLatin_n, chLatin_i, chLatin_n, chLatin_g, chNull };
 
+const XMLCh XML::Literals::SingleLogoutService[] =
+{ chLatin_S, chLatin_i, chLatin_n, chLatin_g, chLatin_l, chLatin_e,
+  chLatin_L, chLatin_o, chLatin_g, chLatin_o, chLatin_u, chLatin_t,
+  chLatin_S, chLatin_e, chLatin_r, chLatin_v, chLatin_i, chLatin_c, chLatin_e, chNull
+};
+
 const XMLCh XML::Literals::SPConfig[] =
 { chLatin_S, chLatin_P, chLatin_C, chLatin_o, chLatin_n, chLatin_f, chLatin_i, chLatin_g, chNull };
 
index 3b43c4e..18bb1d9 100644 (file)
@@ -247,7 +247,7 @@ namespace shibtarget {
             static const XMLCh applicationId[];
             static const XMLCh Application[];
             static const XMLCh Applications[];
-            //static const XMLCh AssertionConsumerService[];
+            static const XMLCh AssertionConsumerService[];
             static const XMLCh CredentialsProvider[];
             static const XMLCh CredentialUse[];
             static const XMLCh Extensions[];
@@ -257,6 +257,8 @@ namespace shibtarget {
             static const XMLCh Host[];
             static const XMLCh htaccess[];
             static const XMLCh Implementation[];
+            static const XMLCh index[];
+            static const XMLCh isDefault[];
             static const XMLCh Library[];
             static const XMLCh Listener[];
             static const XMLCh Local[];
@@ -278,10 +280,12 @@ namespace shibtarget {
             static const XMLCh RevocationProvider[];
             static const XMLCh Rule[];
             static const XMLCh SessionCache[];
+            static const XMLCh SessionInitiator[];
             static const XMLCh SHAR[];
             static const XMLCh ShibbolethTargetConfig[];
             static const XMLCh SHIRE[];
             static const XMLCh Signing[];
+            static const XMLCh SingleLogoutService[];
             static const XMLCh SPConfig[];
             static const XMLCh TCPListener[];
             static const XMLCh TLS[];
index a0dcce0..1a98ebd 100644 (file)
@@ -88,6 +88,7 @@ PlugManager::Factory XMLRequestMapFactory;
 //PlugManager::Factory htaccessFactory;
 
 SAML_EXCEPTION_FACTORY(ListenerException);
+SAML_EXCEPTION_FACTORY(ConfigurationException);
 
 ShibTargetConfig& ShibTargetConfig::getConfig()
 {
@@ -165,6 +166,7 @@ bool STConfig::init(const char* schemadir, const char* config)
     try {
         // Register plugin types.
         REGISTER_EXCEPTION_FACTORY(ListenerException);
+        REGISTER_EXCEPTION_FACTORY(ConfigurationException);
 #ifndef WIN32
         samlConf.getPlugMgr().regFactory(shibtarget::XML::UnixListenerType,&UnixListenerFactory);
 #endif
index fd4a04c..637e09c 100644 (file)
@@ -99,6 +99,11 @@ namespace shibtarget {
         const SAMLBinding* getBinding(const XMLCh* binding) const
             {return XMLString::compareString(SAMLBinding::SOAP,binding) ? NULL : m_binding;}
         SAMLBrowserProfile::ArtifactMapper* getArtifactMapper() const {return new STArtifactMapper(this);}
+        const IPropertySet* getDefaultSessionInitiator() const;
+        const IPropertySet* getSessionInitiatorById(const char* id) const;
+        const IPropertySet* getDefaultAssertionConsumerService() const;
+        const IPropertySet* getAssertionConsumerServiceByIndex(unsigned short index) const;
+        const IPropertySet* getHandler(const char* path) const;
         
         // Provides filter to exclude special config elements.
         short acceptNode(const DOMNode* node) const;
@@ -117,6 +122,11 @@ namespace shibtarget {
         ShibBrowserProfile* m_profile;
         SAMLBinding* m_binding;
         ShibHTTPHook* m_bindingHook;
+        map<string,XMLPropertySet*> m_handlerMap;
+        map<unsigned int,const IPropertySet*> m_acsMap;
+        const IPropertySet* m_acsDefault;
+        map<string,const IPropertySet*> m_sessionInitMap;
+        const IPropertySet* m_sessionInitDefault;
         XMLPropertySet* m_credDefault;
 #ifdef HAVE_GOOD_STL
         map<xstring,XMLPropertySet*> m_credMap;
@@ -168,8 +178,7 @@ namespace shibtarget {
         ISessionCache* getSessionCache() const {return m_sessionCache;}
         IReplayCache* getReplayCache() const {return m_replayCache;}
         IRequestMapper* getRequestMapper() const {return static_cast<XMLConfigImpl*>(m_impl)->m_requestMapper;}
-        const IApplication* getApplication(const char* applicationId) const
-        {
+        const IApplication* getApplication(const char* applicationId) const {
             map<string,IApplication*>::const_iterator i=static_cast<XMLConfigImpl*>(m_impl)->m_appmap.find(applicationId);
             return (i!=static_cast<XMLConfigImpl*>(m_impl)->m_appmap.end()) ? i->second : NULL;
         }
@@ -375,8 +384,13 @@ const IPropertySet* XMLPropertySet::getPropertySet(const char* name, const char*
     return (i!=m_nested.end()) ? i->second : NULL;
 }
 
-XMLApplication::XMLApplication(const IConfig* ini, const Iterator<ICredentials*>& creds, const DOMElement* e, const XMLApplication* base)
-    : m_ini(ini), m_base(base), m_profile(NULL), m_binding(NULL), m_bindingHook(NULL), m_credDefault(NULL)
+XMLApplication::XMLApplication(
+    const IConfig* ini,
+    const Iterator<ICredentials*>& creds,
+    const DOMElement* e,
+    const XMLApplication* base
+    ) : m_ini(ini), m_base(base), m_profile(NULL), m_binding(NULL), m_bindingHook(NULL),
+        m_credDefault(NULL), m_sessionInitDefault(NULL), m_acsDefault(NULL)
 {
 #ifdef _DEBUG
     saml::NDC ndc("XMLApplication");
@@ -387,10 +401,15 @@ XMLApplication::XMLApplication(const IConfig* ini, const Iterator<ICredentials*>
         // First load any property sets.
         map<string,string> root_remap;
         root_remap["shire"]="session";
+        root_remap["shireURL"]="handlerURL";
+        root_remap["shireSSL"]="handlerSSL";
         load(e,log,this,&root_remap);
         const IPropertySet* propcheck=getPropertySet("Errors");
         if (propcheck && !propcheck->getString("session").first)
-            throw MalformedException("<Errors> element requires 'session' (or deprecated 'shire') attribute");
+            throw ConfigurationException("<Errors> element requires 'session' (or deprecated 'shire') attribute");
+        propcheck=getPropertySet("Sessions");
+        if (propcheck && !propcheck->getString("handlerURL").first)
+            throw ConfigurationException("<Sessions> element requires 'handlerURL' (or deprecated 'shireURL') attribute");
 
         m_hash=getId();
         m_hash+=getString("providerId").second;
@@ -398,16 +417,61 @@ XMLApplication::XMLApplication(const IConfig* ini, const Iterator<ICredentials*>
 
         ShibTargetConfig& conf=ShibTargetConfig::getConfig();
         SAMLConfig& shibConf=SAMLConfig::getConfig();
+
+        if (conf.isEnabled(ShibTargetConfig::RequestMapper)) {
+            // Process handlers.
+            bool hardACS=false, hardSessionInit=false;
+            DOMElement* handler=saml::XML::getFirstChildElement(propcheck->getElement());
+            while (handler) {
+                XMLPropertySet* hprops=new XMLPropertySet();
+                hprops->load(handler,log,this); // filter irrelevant for now, no embedded elements expected
+                m_handlerMap[hprops->getString("Location").second]=hprops;
+                
+                // If it's an ACS or SI, handle lookup mappings and defaulting.
+                if (saml::XML::isElementNamed(handler,shibtarget::XML::SAML2META_NS,SHIBT_L(AssertionConsumerService))) {
+                    m_acsMap[hprops->getUnsignedInt("index").second]=hprops;
+                    if (!hardACS) {
+                        pair<bool,bool> defprop=hprops->getBool("isDefault");
+                        if (defprop.first) {
+                            if (defprop.second) {
+                                hardACS=true;
+                                m_acsDefault=hprops;
+                            }
+                        }
+                        else if (!m_acsDefault)
+                            m_acsDefault=hprops;
+                    }
+                }
+                else if (saml::XML::isElementNamed(handler,ShibTargetConfig::SHIBTARGET_NS,SHIBT_L(SessionInitiator))) {
+                    pair<bool,const char*> si_id=hprops->getString("id");
+                    if (si_id.first && si_id.second)
+                        m_sessionInitMap[si_id.second]=hprops;
+                    if (!hardSessionInit) {
+                        pair<bool,bool> defprop=hprops->getBool("isDefault");
+                        if (defprop.first) {
+                            if (defprop.second) {
+                                hardSessionInit=true;
+                                m_sessionInitDefault=hprops;
+                            }
+                        }
+                        else if (!m_sessionInitDefault)
+                            m_sessionInitDefault=hprops;
+                    }
+                }
+                handler=saml::XML::getNextSiblingElement(handler);
+            }
+        }
+        
+        // Process general configuration elements.
         int i;
         DOMNodeList* nlist=e->getElementsByTagNameNS(saml::XML::SAML_NS,L(AttributeDesignator));
-        for (i=0; nlist && i<nlist->getLength(); i++) {
+        for (i=0; nlist && i<nlist->getLength(); i++)
             m_designators.push_back(new SAMLAttributeDesignator(static_cast<DOMElement*>(nlist->item(i))));
-        }
 
         nlist=e->getElementsByTagNameNS(saml::XML::SAML_NS,L(Audience));
-        for (i=0; nlist && i<nlist->getLength(); i++) {
+        for (i=0; nlist && i<nlist->getLength(); i++)
             m_audiences.push_back(nlist->item(i)->getFirstChild()->getNodeValue());
-        }
+
         // Always include our own providerId as an audience.
         m_audiences.push_back(getXMLString("providerId").second);
 
@@ -530,6 +594,11 @@ void XMLApplication::cleanup()
     delete m_bindingHook;
     delete m_binding;
     delete m_profile;
+    map<string,XMLPropertySet*>::iterator h=m_handlerMap.begin();
+    while (h!=m_handlerMap.end()) {
+        delete h->second;
+        h++;
+    }
     delete m_credDefault;
 #ifdef HAVE_GOOD_STL
     map<xstring,XMLPropertySet*>::iterator c=m_credMap.begin();
@@ -567,6 +636,9 @@ short XMLApplication::acceptNode(const DOMNode* node) const
         return FILTER_ACCEPT;
     const XMLCh* name=node->getLocalName();
     if (!XMLString::compareString(name,SHIBT_L(Application)) ||
+        !XMLString::compareString(name,SHIBT_L(AssertionConsumerService)) ||
+        !XMLString::compareString(name,SHIBT_L(SingleLogoutService)) ||
+        !XMLString::compareString(name,SHIBT_L(SessionInitiator)) ||
         !XMLString::compareString(name,SHIBT_L(AAPProvider)) ||
         !XMLString::compareString(name,SHIBT_L(CredentialUse)) ||
         !XMLString::compareString(name,SHIBT_L(RelyingParty)) ||
@@ -690,6 +762,39 @@ const IPropertySet* XMLApplication::getCredentialUse(const IEntityDescriptor* pr
     return m_credDefault;
 }
 
+const IPropertySet* XMLApplication::getDefaultSessionInitiator() const
+{
+    if (m_sessionInitDefault) return m_sessionInitDefault;
+    return m_base ? m_base->getDefaultSessionInitiator() : NULL;
+}
+
+const IPropertySet* XMLApplication::getSessionInitiatorById(const char* id) const
+{
+    map<string,const IPropertySet*>::const_iterator i=m_sessionInitMap.find(id);
+    if (i!=m_sessionInitMap.end()) return i->second;
+    return m_base ? m_base->getSessionInitiatorById(id) : NULL;
+}
+
+const IPropertySet* XMLApplication::getDefaultAssertionConsumerService() const
+{
+    if (m_acsDefault) return m_acsDefault;
+    return m_base ? m_base->getDefaultAssertionConsumerService() : NULL;
+}
+
+const IPropertySet* XMLApplication::getAssertionConsumerServiceByIndex(unsigned short index) const
+{
+    map<unsigned int,const IPropertySet*>::const_iterator i=m_acsMap.find(index);
+    if (i!=m_acsMap.end()) return i->second;
+    return m_base ? m_base->getAssertionConsumerServiceByIndex(index) : NULL;
+}
+
+const IPropertySet* XMLApplication::getHandler(const char* path) const
+{
+    string wrap(path);
+    map<string,XMLPropertySet*>::const_iterator i=m_handlerMap.find(wrap.substr(0,wrap.find('?')));
+    return (i!=m_handlerMap.end()) ? i->second : NULL;
+}
+
 ReloadableXMLFileImpl* XMLConfig::newImplementation(const char* pathname, bool first) const
 {
     return new XMLConfigImpl(pathname,first,this);
@@ -735,7 +840,7 @@ void XMLConfigImpl::init(bool first)
         if (!saml::XML::isElementNamed(ReloadableXMLFileImpl::m_root,ShibTargetConfig::SHIBTARGET_NS,SHIBT_L(ShibbolethTargetConfig)) &&
             !saml::XML::isElementNamed(ReloadableXMLFileImpl::m_root,ShibTargetConfig::SHIBTARGET_NS,SHIBT_L(SPConfig))) {
             log.error("Construction requires a valid configuration file: (conf:SPConfig as root element)");
-            throw MalformedException("Construction requires a valid configuration file: (conf:SPConfig as root element)");
+            throw ConfigurationException("Construction requires a valid configuration file: (conf:SPConfig as root element)");
         }
 
         SAMLConfig& shibConf=SAMLConfig::getConfig();
@@ -872,7 +977,7 @@ void XMLConfigImpl::init(bool first)
                         }
                         else {
                             log.fatal("can't build Listener object, missing conf:Listener element?");
-                            throw MalformedException("can't build Listener object, missing conf:Listener element?");
+                            throw ConfigurationException("can't build Listener object, missing conf:Listener element?");
                         }
                     }
                 }
@@ -910,7 +1015,7 @@ void XMLConfigImpl::init(bool first)
                         }
                         else {
                             log.fatal("can't build Session Cache object, missing conf:SessionCache element?");
-                            throw MalformedException("can't build Session Cache object, missing conf:SessionCache element?");
+                            throw ConfigurationException("can't build Session Cache object, missing conf:SessionCache element?");
                         }
                     }
                 }
@@ -967,7 +1072,7 @@ void XMLConfigImpl::init(bool first)
             }
             else {
                 log.fatal("can't build Request Mapper object, missing conf:RequestMapProvider element?");
-                throw MalformedException("can't build Request Mapper object, missing conf:RequestMapProvider element?");
+                throw ConfigurationException("can't build Request Mapper object, missing conf:RequestMapProvider element?");
             }
         }
         
@@ -1000,7 +1105,7 @@ void XMLConfigImpl::init(bool first)
             );
         if (!app) {
             log.fatal("can't build default Application object, missing conf:Applications element?");
-            throw SAMLException("can't build default Application object, missing conf:Applications element?");
+            throw ConfigurationException("can't build default Application object, missing conf:Applications element?");
         }
         XMLApplication* defapp=new XMLApplication(m_outer, m_creds, app);
         m_appmap[defapp->getId()]=defapp;
@@ -1011,7 +1116,7 @@ void XMLConfigImpl::init(bool first)
             XMLApplication* iapp=new XMLApplication(m_outer,m_creds,static_cast<DOMElement*>(nlist->item(i)),defapp);
             if (m_appmap.find(iapp->getId())!=m_appmap.end()) {
                 log.fatal("found conf:Application element with duplicate Id attribute");
-                throw SAMLException("found conf:Application element with duplicate Id attribute");
+                throw ConfigurationException("found conf:Application element with duplicate Id attribute");
             }
             m_appmap[iapp->getId()]=iapp;
         }
index 826fb2c..e6bd1b7 100644 (file)
@@ -107,18 +107,32 @@ namespace shibtarget {
     ShibTargetPriv();
     ~ShibTargetPriv();
 
+    // Helper functions
     void get_application(const string& protocol, const string& hostname, int port, const string& uri);
-    const char* getCookie(ShibTarget* st, const string& name);
-    //const char* getSessionId(ShibTarget* st);
-    //const char* getRelayState(ShibTarget* st);
+    const char* getCookie(ShibTarget* st, const string& name) const;
+    pair<string,const char*> getCookieNameProps(const char* prefix) const;
+    const char* getHandlerURL(const char* resource) const;
+    
+    // Handlers do the real Shibboleth work
+    pair<bool,void*> doSessionInitiator(ShibTarget* st, const IPropertySet* handler, bool isHandler=true) const;
+    pair<bool,void*> doAssertionConsumer(ShibTarget* st, const IPropertySet* handler) const;
+    pair<bool,void*> doLogout(ShibTarget* st, const IPropertySet* handler) const;
+
+    // And the binding/profile handlers do the low level packing and unpacking.
+    pair<bool,void*> ShibAuthnRequest(
+        ShibTarget* st,
+        const IPropertySet* shire,
+        const char* dest,
+        const char* target,
+        const char* providerId
+        ) const;
 
   private:
     friend class ShibTarget;
     IRequestMapper::Settings m_settings;
     const IApplication *m_app;
-    string m_shireURL;
-
-    map<string,string> m_cookieMap;
+    mutable string m_handlerURL;
+    mutable map<string,string> m_cookieMap;
 
     ShibProfile m_sso_profile;
     string m_provider_id;
@@ -173,7 +187,7 @@ void ShibTarget::init(
     )
 {
 #ifdef _DEBUG
-  saml::NDC ndc("ShibTarget::init");
+  saml::NDC ndc("init");
 #endif
 
   if (m_priv->m_app)
@@ -193,29 +207,30 @@ void ShibTarget::init(
 // 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,void*>
-ShibTarget::doCheckAuthN(bool requireSessionFlag, bool handleProfile)
+
+pair<bool,void*> ShibTarget::doCheckAuthN(bool requireSessionFlag, bool handler)
 {
 #ifdef _DEBUG
-    saml::NDC ndc("ShibTarget::doCheckAuthN");
+    saml::NDC ndc("doCheckAuthN");
 #endif
 
-    const char *targetURL = NULL;
-    const char *procState = "Request Setup Error";
+    const char *procState = "Request Processing Error";
+    const char *targetURL = m_priv->m_url.c_str();
     ShibMLP mlp;
 
     try {
         if (!m_priv->m_app)
-            throw SAMLException("System uninitialized, application did not supply request information.");
+            throw ConfigurationException("System uninitialized, application did not supply request information.");
 
-        targetURL = m_priv->m_url.c_str();
-        const char *shireURL = getShireURL(targetURL);
-        if (!shireURL)
-            throw SAMLException("Cannot determine assertion consumer service from resource URL, check configuration.");
+        const char* handlerURL = m_priv->getHandlerURL(targetURL);
+        if (!handlerURL)
+            throw ConfigurationException("Cannot determine handler from resource URL, check configuration.");
 
-        if (strstr(targetURL,shireURL)) {
-            if (handleProfile)
-                return doHandleProfile();
+        // 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,handlerURL)) {
+            if (handler)
+                return doHandler();
             else
                 return pair<bool,void*>(true, returnOK());
         }
@@ -231,15 +246,17 @@ ShibTarget::doCheckAuthN(bool requireSessionFlag, bool handleProfile)
                 requireSession.second=true;
         }
 
-        pair<string,const char*> shib_cookie = getCookieNameProps("_shibsession_");
+        pair<string,const char*> shib_cookie = m_priv->getCookieNameProps("_shibsession_");
         const char* session_id = m_priv->getCookie(this,shib_cookie.first);
         if (!session_id || !*session_id) {
             // No session.  Maybe that's acceptable?
             if (!requireSession.second)
                 return pair<bool,void*>(true,returnOK());
 
-            // No cookie, but we require a session.  Generate an AuthnRequest.
-            return pair<bool,void*>(true,sendRedirect(getAuthnRequest(targetURL)));
+            // No cookie, but we require a session. Initiate a new session using the default method.
+            procState = "Session Initiator Error";
+            const IPropertySet* initiator=m_priv->m_app->getDefaultSessionInitiator();
+            return m_priv->doSessionInitiator(this, initiator ? initiator : m_priv->m_app->getPropertySet("Sessions"), false);
         }
 
         procState = "Session Processing Error";
@@ -265,11 +282,20 @@ ShibTarget::doCheckAuthN(bool requireSessionFlag, bool handleProfile)
                 // AuthType.  No session plus requireSession false means
                 // do not authenticate the user at this time.
                 return pair<bool,void*>(true, returnOK());
-            
-            // TODO: need to test this...may need an actual reference cast
-            if (typeid(e)==typeid(RetryableProfileException)) {
-                // Session is invalid but we can retry -- generate an AuthnRequest
-                return pair<bool,void*>(true,sendRedirect(getAuthnRequest(targetURL)));
+
+            // Try and cast down. This should throw an exception if it fails.
+            bool retryable=false;
+            try {
+                RetryableProfileException& trycast=dynamic_cast<RetryableProfileException&>(e);
+                retryable=true;
+            }
+            catch (exception&) {
+            }
+            if (retryable) {
+                // Session is invalid but we can retry -- initiate a new session.
+                procState = "Session Initiator Error";
+                const IPropertySet* initiator=m_priv->m_app->getDefaultSessionInitiator();
+                return m_priv->doSessionInitiator(this, initiator ? initiator : m_priv->m_app->getPropertySet("Sessions"), false);
             }
             throw;    // send it to the outer handler
         }
@@ -291,127 +317,77 @@ ShibTarget::doCheckAuthN(bool requireSessionFlag, bool handleProfile)
     // If we get here then we've got an error.
     mlp.insert("errorType", procState);
     if (targetURL)
-        mlp.insert("requestURL", targetURL);
+        mlp.insert("requestURL", m_priv->m_url.substr(0,m_priv->m_url.find('?')));
 
     return pair<bool,void*>(true,sendError("session", mlp));
 }
 
-pair<bool,void*>
-ShibTarget::doHandleProfile(void)
+pair<bool,void*> ShibTarget::doHandler(void)
 {
 #ifdef _DEBUG
-    saml::NDC ndc("ShibTarget::doHandleProfile");
+    saml::NDC ndc("doHandler");
 #endif
 
-    const char *targetURL = NULL;
-    const char *procState = "Session Creation Service Error";
+    const char *procState = "Shibboleth Handler Error";
+    const char* targetURL = m_priv->m_url.c_str();
     ShibMLP mlp;
 
     try {
         if (!m_priv->m_app)
-            throw SAMLException("System uninitialized, application did not supply request information.");
-
-        targetURL = m_priv->m_url.c_str();
-        const char* shireURL = getShireURL(targetURL);
+            throw ConfigurationException("System uninitialized, application did not supply request information.");
 
-        if (!shireURL)
-            throw SAMLException("Cannot determine assertion consumer service, check configuration.");
+        const char* handlerURL = m_priv->getHandlerURL(targetURL);
+        if (!handlerURL)
+            throw ConfigurationException("Cannot determine handler from resource URL, check configuration.");
 
-        // Make sure we only process the SHIRE requests.
-        if (!strstr(targetURL, shireURL))
+        // Make sure we only process handler requests.
+        if (!strstr(targetURL,handlerURL))
             return pair<bool,void*>(true, returnDecline());
 
         const IPropertySet* sessionProps=m_priv->m_app->getPropertySet("Sessions");
         if (!sessionProps)
-            throw SAMLException("Unable to map request to application session settings, check configuration.");
+            throw ConfigurationException("Unable to map request to application session settings, check configuration.");
 
         // Process incoming request.
-        pair<bool,bool> shireSSL=sessionProps->getBool("handlerSSL");
+        pair<bool,bool> handlerSSL=sessionProps->getBool("handlerSSL");
       
         // Make sure this is SSL, if it should be
-        if ((!shireSSL.first || shireSSL.second) && m_priv->m_protocol != "https")
-            throw FatalProfileException("Blocked non-SSL access to session creation service.");
-
-        // If this is a GET, we see if it's a lazy session request, otherwise
-        // assume it's a profile response and process it.
-        string cgistr;
-        if (!strcasecmp(m_priv->m_method.c_str(), "GET")) {
-            cgistr = getArgs();
-            string areq;
-            if (!cgistr.empty())
-                areq=getLazyAuthnRequest(cgistr.c_str());
-            if (!areq.empty())
-                return pair<bool,void*>(true, sendRedirect(areq));
-        }
-        else if (!strcasecmp(m_priv->m_method.c_str(), "POST")) {
-            if (m_priv->m_content_type.empty() || strcasecmp(m_priv->m_content_type.c_str(),"application/x-www-form-urlencoded")) {
-                throw FatalProfileException(
-                    "Blocked invalid POST content-type ($1) to session creation service.",
-                    params(1,m_priv->m_content_type.c_str())
-                    );
-            }
-            // Read the POST Data
-            cgistr = getPostData();
-        }
-       
-        // Process the submission
-        string cookie,target,providerId;
-        try {
-            sessionNew(
-                SAML11_POST | SAML11_ARTIFACT,
-                cgistr.c_str(),
-                m_priv->m_remote_addr.c_str(),
-                target,
-                cookie,
-                providerId
-                );
-        }
-        catch (SAMLException& e) {
-            log(LogLevelError, string("profile processing failed: ") + e.what());
-    
-            // TODO: need to test this...may need an actual reference cast
-            if (typeid(e)==typeid(RetryableProfileException)) {
-                return pair<bool,void*>(true, sendRedirect(getAuthnRequest(target.c_str())));
+        if ((!handlerSSL.first || handlerSSL.second) && m_priv->m_protocol != "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 IPropertySet* handler=m_priv->m_app->getHandler(targetURL + strlen(handlerURL));
+        if (handler) {
+            if (saml::XML::isElementNamed(handler->getElement(),shibtarget::XML::SAML2META_NS,SHIBT_L(AssertionConsumerService))) {
+                procState = "Session Creation Error";
+                return m_priv->doAssertionConsumer(this,handler);
             }
-            throw;    // send it to the outer handler
-        }
-
-        log(LogLevelDebug, string("profile processing succeeded, new session created (") + cookie + ")");
-
-        if (target=="default") {
-            pair<bool,const char*> homeURL=m_priv->m_app->getString("homeURL");
-            target=homeURL.first ? homeURL.second : "/";
-        }
-        else if (target=="cookie") {
-            // Pull the target value from the "relay state" cookie.
-            pair<string,const char*> relay_cookie = getCookieNameProps("_shibstate_");
-            const char* relay_state = m_priv->getCookie(this,relay_cookie.first);
-            if (!relay_state || !*relay_state) {
-                // No apparent relay state value to use, so fall back on the default.
-                pair<bool,const char*> homeURL=m_priv->m_app->getString("homeURL");
-                target=homeURL.first ? homeURL.second : "/";
+            else if (saml::XML::isElementNamed(handler->getElement(),ShibTargetConfig::SHIBTARGET_NS,SHIBT_L(SessionInitiator))) {
+                procState = "Session Initiator Error";
+                return m_priv->doSessionInitiator(this,handler);
             }
-            else {
-                char* rscopy=strdup(relay_state);
-                CgiParse::url_decode(rscopy);
-                target=rscopy;
-                free(rscopy);
+            else if (saml::XML::isElementNamed(handler->getElement(),shibtarget::XML::SAML2META_NS,SHIBT_L(SingleLogoutService))) {
+                procState = "Session Termination Error";
+                return m_priv->doLogout(this,handler);
             }
+            else
+                throw ConfigurationException("Endpoint is mapped to unrecognized handler element.");
         }
-    
-        // We've got a good session, set the session cookie.
-        pair<string,const char*> shib_cookie=getCookieNameProps("_shibsession_");
-        setCookie(shib_cookie.first, cookie + shib_cookie.second);
-
-        pair<bool,bool> idpHistory=sessionProps->getBool("idpHistory");
-        if (!idpHistory.first || idpHistory.second) {
-            // Set an IdP history cookie locally (essentially just a CDC).
-            CommonDomainCookie cdc(m_priv->getCookie(this,CommonDomainCookie::CDCName));
-            setCookie(CommonDomainCookie::CDCName,string(cdc.set(providerId.c_str())) + shib_cookie.second);
+        
+        if (strlen(targetURL)>strlen(handlerURL) && targetURL[strlen(handlerURL)]!='?')
+            throw SAMLException("Shibboleth handler invoked at an unconfigured location.");
+        
+        // This is a legacy direct execution of the handler (the old shireURL).
+        // If this is a GET, we see if it's a lazy session request, otherwise
+        // assume it's a SAML 1.x POST profile response and process it.
+        if (!strcasecmp(m_priv->m_method.c_str(), "GET")) {
+            procState = "Session Initiator Error";
+            return m_priv->doSessionInitiator(this, sessionProps);
         }
-
-        // Now redirect to the target.
-        return pair<bool,void*>(true, sendRedirect(target));
+        
+        procState = "Session Creation Error";
+        return m_priv->doAssertionConsumer(this, sessionProps);
     }
     catch (MetadataException& e) {
         mlp.insert(e);
@@ -440,27 +416,24 @@ ShibTarget::doHandleProfile(void)
     mlp.insert("errorType", procState);
 
     if (targetURL)
-        mlp.insert("requestURL", targetURL);
+        mlp.insert("requestURL", m_priv->m_url.substr(0,m_priv->m_url.find('?')));
 
     return pair<bool,void*>(true,sendError("session", mlp));
 }
 
-pair<bool,void*>
-ShibTarget::doCheckAuthZ(void)
+pair<bool,void*> ShibTarget::doCheckAuthZ(void)
 {
 #ifdef _DEBUG
-    saml::NDC ndc("ShibTarget::doCheckAuthZ");
+    saml::NDC ndc("doCheckAuthZ");
 #endif
 
     ShibMLP mlp;
     const char *procState = "Authorization Processing Error";
-    const char *targetURL = NULL;
+    const char *targetURL = m_priv->m_url.c_str();
 
     try {
         if (!m_priv->m_app)
-            throw SAMLException("System uninitialized, application did not supply request information.");
-
-        targetURL = m_priv->m_url.c_str();
+            throw ConfigurationException("System uninitialized, application did not supply request information.");
 
         // Do we have an access control plugin?
         if (m_priv->m_settings.second) {
@@ -677,28 +650,26 @@ ShibTarget::doCheckAuthZ(void)
     mlp.insert("errorType", procState);
 
     if (targetURL)
-        mlp.insert("requestURL", targetURL);
+        mlp.insert("requestURL", m_priv->m_url.substr(0,m_priv->m_url.find('?')));
 
     return pair<bool,void*>(true,sendError("access", mlp));
 }
 
-pair<bool,void*>
-ShibTarget::doExportAssertions(bool exportAssertion)
+pair<bool,void*> ShibTarget::doExportAssertions(bool exportAssertion)
 {
 #ifdef _DEBUG
-    saml::NDC ndc("ShibTarget::doExportAssertions");
+    saml::NDC ndc("doExportAssertions");
 #endif
 
     ShibMLP mlp;
     const char *procState = "Attribute Processing Error";
-    const char *targetURL = NULL;
+    const char *targetURL = m_priv->m_url.c_str();
 
     try {
         if (!m_priv->m_app)
-            throw SAMLException("System uninitialized, application did not supply request information.");
+            throw ConfigurationException("System uninitialized, application did not supply request information.");
 
-        targetURL = m_priv->m_url.c_str();
-        pair<string,const char*> shib_cookie=getCookieNameProps("_shibsession_");
+        pair<string,const char*> shib_cookie=m_priv->getCookieNameProps("_shibsession_");
         const char *session_id = m_priv->getCookie(this,shib_cookie.first);
 
         if (!m_priv->m_sso_statement) {
@@ -844,165 +815,15 @@ ShibTarget::doExportAssertions(bool exportAssertion)
     mlp.insert("errorType", procState);
 
     if (targetURL)
-        mlp.insert("requestURL", targetURL);
+        mlp.insert("requestURL", m_priv->m_url.substr(0,m_priv->m_url.find('?')));
 
     return pair<bool,void*>(true,sendError("rm", mlp));
 }
 
 
-// Low level APIs
-
-// Get the session cookie name and properties for the application
-pair<string,const char*> ShibTarget::getCookieNameProps(const char* prefix) const
-{
-    static const char* defProps="; path=/";
-    
-    const IPropertySet* props=m_priv->m_app ? m_priv->m_app->getPropertySet("Sessions") : NULL;
-    if (props) {
-        pair<bool,const char*> p=props->getString("cookieProps");
-        if (!p.first)
-            p.second=defProps;
-        pair<bool,const char*> p2=props->getString("cookieName");
-        if (p2.first)
-            return make_pair(string(prefix) + p2.second,p.second);
-        return make_pair(string(prefix) + m_priv->m_app->getHash(),p.second);
-    }
-    
-    // Shouldn't happen, but just in case..
-    return make_pair(prefix,defProps);
-}
-        
-// Find the default assertion consumer service for the resource
-const char*
-ShibTarget::getShireURL(const char* resource) const
-{
-    if (!m_priv->m_shireURL.empty())
-        return m_priv->m_shireURL.c_str();
-
-    // XXX: what to do is m_app is NULL?
-
-    bool shire_ssl_only=false;
-    const char* shire=NULL;
-    const IPropertySet* props=m_priv->m_app->getPropertySet("Sessions");
-    if (props) {
-        pair<bool,bool> p=props->getBool("handlerSSL");
-        if (p.first)
-            shire_ssl_only=p.second;
-        pair<bool,const char*> p2=props->getString("handlerURL");
-        if (p2.first)
-            shire=p2.second;
-    }
-    
-    // Should never happen...
-    if (!shire || (*shire!='/' && strncmp(shire,"http:",5) && strncmp(shire,"https:",6)))
-        return NULL;
-
-    // The "shireURL" property can be in one of three formats:
-    //
-    // 1) a full URI:       http://host/foo/bar
-    // 2) a hostless URI:   http:///foo/bar
-    // 3) a relative path:  /foo/bar
-    //
-    // #  Protocol  Host        Path
-    // 1  shire     shire       shire
-    // 2  shire     resource    shire
-    // 3  resource  resource    shire
-    //
-    // note: if shire_ssl_only is true, make sure the protocol is https
-
-    const char* path = NULL;
-
-    // Decide whether to use the shire or the resource for the "protocol"
-    const char* prot;
-    if (*shire != '/') {
-        prot = shire;
-    }
-    else {
-        prot = resource;
-        path = shire;
-    }
-
-    // break apart the "protocol" string into protocol, host, and "the rest"
-    const char* colon=strchr(prot,':');
-    colon += 3;
-    const char* slash=strchr(colon,'/');
-    if (!path)
-        path = slash;
-
-    // Compute the actual protocol and store in member.
-    if (shire_ssl_only)
-        m_priv->m_shireURL.assign("https://");
-    else
-        m_priv->m_shireURL.assign(prot, colon-prot);
-
-    // create the "host" from either the colon/slash or from the target string
-    // If prot == shire then we're in either #1 or #2, else #3.
-    // If slash == colon then we're in #2.
-    if (prot != shire || slash == colon) {
-        colon = strchr(resource, ':');
-        colon += 3;      // Get past the ://
-        slash = strchr(colon, '/');
-    }
-    string host(colon, slash-colon);
-
-    // Build the shire URL
-    m_priv->m_shireURL+=host + path;
-    return m_priv->m_shireURL.c_str();
-}
-        
-// Generate a Shib 1.x AuthnRequest redirect URL for the resource,
-// using whatever relay state mechanism is specified for the app.
-string ShibTarget::getAuthnRequest(const char* resource)
-{
-    // XXX: what to do if m_app is NULL?
-
-    string req;
-    char timebuf[16];
-    sprintf(timebuf,"%u",time(NULL));
-    
-    const IPropertySet* props=m_priv->m_app ? m_priv->m_app->getPropertySet("Sessions") : NULL;
-    if (props) {
-        pair<bool,const char*> wayf=props->getString("wayfURL");
-        if (wayf.first) {
-            req=req + wayf.second + "?shire=" + CgiParse::url_encode(getShireURL(resource)) + "&time=" + timebuf;
-            
-            // How should the target value be preserved?
-            pair<bool,bool> localRelayState=m_priv->m_conf->getPropertySet("Local")->getBool("localRelayState");
-            if (!localRelayState.first || !localRelayState.second) {
-                // The old way, just send it along.
-                req = req + "&target=" + CgiParse::url_encode(resource);
-            }
-            else {
-                // Here we store the state in a cookie and send a fixed
-                // value to the IdP so we can recognize it on the way back.
-                pair<string,const char*> shib_cookie=getCookieNameProps("_shibstate_");
-                setCookie(shib_cookie.first,CgiParse::url_encode(resource) + shib_cookie.second);
-                req += "&target=cookie";
-            }
-            
-            pair<bool,bool> old=m_priv->m_app->getBool("oldAuthnRequest");
-            if (!old.first || !old.second) {
-                wayf=m_priv->m_app->getString("providerId");
-                if (wayf.first)
-                    req=req + "&providerId=" + CgiParse::url_encode(wayf.second);
-            }
-        }
-    }
-    return req;
-}
-        
-// Process a lazy session setup request and turn it into an AuthnRequest
-string ShibTarget::getLazyAuthnRequest(const char* query_string)
-{
-    CgiParse parser(query_string,strlen(query_string));
-    const char* target=parser.get_value("target");
-    if (!target || !*target)
-        return "";
-    return getAuthnRequest(target);
-}
-
 void ShibTarget::sessionNew(
     int supported_profiles,
+    const string& recipient,
     const char* packet,
     const char* ip,
     string& target,
@@ -1031,8 +852,8 @@ void ShibTarget::sessionNew(
     }
   
     shibrpc_new_session_args_2 arg;
-    arg.recipient = (char*) m_priv->m_shireURL.c_str();
-    arg.application_id = (char*) m_priv->m_app->getId();
+    arg.recipient = (char*)recipient.c_str();
+    arg.application_id = (char*)m_priv->m_app->getId();
     arg.packet = (char*)packet;
     arg.client_addr = (char*)ip;
     arg.supported_profiles = supported_profiles;
@@ -1105,7 +926,7 @@ void ShibTarget::sessionNew(
     rpc.pool();
     if (except) {
         auto_ptr<SAMLException> wrapper(except);
-        throw *wrapper;
+        wrapper->raise();
     }
 }
 
@@ -1247,7 +1068,7 @@ void ShibTarget::sessionGet(
     rpc.pool();
     if (except) {
         auto_ptr<SAMLException> wrapper(except);
-        throw *wrapper;
+        wrapper->raise();
     }
 }
 
@@ -1305,8 +1126,7 @@ ShibTargetPriv::~ShibTargetPriv()
   m_Config = NULL;
 }
 
-void
-ShibTargetPriv::get_application(const string& protocol, const string& hostname, int port, const string& uri)
+void ShibTargetPriv::get_application(const string& protocol, const string& hostname, int port, const string& uri)
 {
   if (m_app)
     return;
@@ -1348,7 +1168,7 @@ ShibTargetPriv::get_application(const string& protocol, const string& hostname,
   m_url += uri;
 }
 
-const char* ShibTargetPriv::getCookie(ShibTarget* st, const string& name)
+const char* ShibTargetPriv::getCookie(ShibTarget* st, const string& name) const
 {
     if (m_cookieMap.empty()) {
         string cookies=st->getCookies();
@@ -1379,6 +1199,351 @@ const char* ShibTargetPriv::getCookie(ShibTarget* st, const string& name)
     return (lookup==m_cookieMap.end()) ? NULL : lookup->second.c_str();
 }
 
+// Get the session cookie name and properties for the application
+pair<string,const char*> ShibTargetPriv::getCookieNameProps(const char* prefix) const
+{
+    static const char* defProps="; path=/";
+    
+    const IPropertySet* props=m_app ? m_app->getPropertySet("Sessions") : NULL;
+    if (props) {
+        pair<bool,const char*> p=props->getString("cookieProps");
+        if (!p.first)
+            p.second=defProps;
+        pair<bool,const char*> p2=props->getString("cookieName");
+        if (p2.first)
+            return make_pair(string(prefix) + p2.second,p.second);
+        return make_pair(string(prefix) + m_app->getHash(),p.second);
+    }
+    
+    // Shouldn't happen, but just in case..
+    return make_pair(prefix,defProps);
+}
+
+const char* ShibTargetPriv::getHandlerURL(const char* resource) const
+{
+    if (!m_handlerURL.empty())
+        return m_handlerURL.c_str();
+
+    if (!m_app)
+        throw ConfigurationException("Internal error in ShibTargetPriv::getHandlerURL, missing application pointer.");
+
+    bool ssl_only=false;
+    const char* handler=NULL;
+    const IPropertySet* props=m_app->getPropertySet("Sessions");
+    if (props) {
+        pair<bool,bool> p=props->getBool("handlerSSL");
+        if (p.first)
+            ssl_only=p.second;
+        pair<bool,const char*> p2=props->getString("handlerURL");
+        if (p2.first)
+            handler=p2.second;
+    }
+    
+    // Should never happen...
+    if (!handler || (*handler!='/' && strncmp(handler,"http:",5) && strncmp(handler,"https:",6)))
+        throw ConfigurationException(
+            "Invalid handlerURL property ($1) in Application ($2)",
+            params(2, handler ? handler : "null", m_app->getId())
+            );
+
+    // The "handlerURL" property can be in one of three formats:
+    //
+    // 1) a full URI:       http://host/foo/bar
+    // 2) a hostless URI:   http:///foo/bar
+    // 3) a relative path:  /foo/bar
+    //
+    // #  Protocol  Host        Path
+    // 1  handler   handler     handler
+    // 2  handler   resource    handler
+    // 3  resource  resource    handler
+    //
+    // note: if ssl_only is true, make sure the protocol is https
+
+    const char* path = NULL;
+
+    // Decide whether to use the handler or the resource for the "protocol"
+    const char* prot;
+    if (*handler != '/') {
+        prot = handler;
+    }
+    else {
+        prot = resource;
+        path = handler;
+    }
+
+    // break apart the "protocol" string into protocol, host, and "the rest"
+    const char* colon=strchr(prot,':');
+    colon += 3;
+    const char* slash=strchr(colon,'/');
+    if (!path)
+        path = slash;
+
+    // Compute the actual protocol and store in member.
+    if (ssl_only)
+        m_handlerURL.assign("https://");
+    else
+        m_handlerURL.assign(prot, colon-prot);
+
+    // create the "host" from either the colon/slash or from the target string
+    // If prot == handler then we're in either #1 or #2, else #3.
+    // If slash == colon then we're in #2.
+    if (prot != handler || slash == colon) {
+        colon = strchr(resource, ':');
+        colon += 3;      // Get past the ://
+        slash = strchr(colon, '/');
+    }
+    string host(colon, slash-colon);
+
+    // Build the shire URL
+    m_handlerURL+=host + path;
+    return m_handlerURL.c_str();
+}
+
+pair<bool,void*> ShibTargetPriv::doSessionInitiator(ShibTarget* st, const IPropertySet* handler, bool isHandler) const
+{
+    string dupresource;
+    const char* resource=NULL;
+    const IPropertySet* ACS=NULL;
+    
+    if (isHandler) {
+        // We're running as an actual handler, so check to see if we understand the binding.
+        pair<bool,const XMLCh*> binding=handler->getXMLString("Binding");
+        if (binding.first && XMLString::compareString(binding.second,Constants::SHIB_SESSIONINIT_PROFILE_URI))
+            throw UnsupportedProfileException(
+                "Unsupported session initiator binding ($1).", params(1,handler->getString("Binding").second)
+                );
+        
+        /* 
+         * Binding is CGI query string with:
+         *  target      the resource to direct back to later
+         *  acsIndex    optional index of an ACS to use on the way back in
+         *  providerId  optional direct invocation of a specific IdP
+         */
+        string query=st->getArgs();
+        CgiParse parser(query.c_str(),query.length());
+
+        const char* option=parser.get_value("acsIndex");
+        if (option)
+            ACS=m_app->getAssertionConsumerServiceByIndex(atoi(option));
+        option=parser.get_value("providerId");
+        
+        resource=parser.get_value("target");
+        if (!resource || !*resource) {
+            pair<bool,const char*> home=m_app->getString("homeURL");
+            if (home.first)
+                resource=home.second;
+            else
+                throw FatalProfileException("Session initiator requires a target parameter or a homeURL application property.");
+        }
+        else if (!option) {
+            dupresource=resource;
+            resource=dupresource.c_str();
+        }
+        
+        if (option) {
+            // Here we actually use metadata to invoke the SSO service directly.
+            // The only currently understood binding is the Shibboleth profile.
+            Metadata m(m_app->getMetadataProviders());
+            const IEntityDescriptor* entity=m.lookup(option);
+            if (!entity)
+                throw MetadataException("Session initiator unable to locate metadata for provider ($1).", params(1,option));
+            const IIDPSSODescriptor* role=entity->getIDPSSODescriptor(saml::XML::SAML11_PROTOCOL_ENUM);
+            if (!role)
+                throw MetadataException(
+                    "Session initiator unable to locate SAML identity provider role for provider ($1).", params(1,option)
+                    );
+            const IEndpointManager* SSO=role->getSingleSignOnServiceManager();
+            const IEndpoint* ep=SSO->getEndpointByBinding(Constants::SHIB_AUTHNREQUEST_PROFILE_URI);
+            if (!ep)
+                throw MetadataException(
+                    "Session initiator unable to locate compatible SSO service for provider ($1).", params(1,option)
+                    );
+            auto_ptr_char dest(ep->getLocation());
+            return ShibAuthnRequest(
+                st,ACS ? ACS : m_app->getDefaultAssertionConsumerService(),dest.get(),resource,m_app->getString("providerId").second
+                );
+        }
+    }
+    else {
+        // We're running as a "virtual handler" from within the filter.
+        // The target resource is the current one and everything else is defaulted.
+        resource=m_url.c_str();
+    }
+    
+    if (!ACS) ACS=m_app->getDefaultAssertionConsumerService();
+    
+    // For now, we only support external session initiation via a wayfURL
+    pair<bool,const char*> wayfURL=handler->getString("wayfURL");
+    if (!wayfURL.first)
+        throw ConfigurationException("Session initiator is missing wayfURL property.");
+
+    pair<bool,const XMLCh*> wayfBinding=handler->getXMLString("wayfBinding");
+    if (!wayfBinding.first || !XMLString::compareString(wayfBinding.second,Constants::SHIB_AUTHNREQUEST_PROFILE_URI))
+        // Standard Shib 1.x
+        return ShibAuthnRequest(st,ACS,wayfURL.second,resource,m_app->getString("providerId").second);
+    else if (!XMLString::compareString(wayfBinding.second,Constants::SHIB_LEGACY_AUTHNREQUEST_PROFILE_URI))
+        // Shib pre-1.2
+        return ShibAuthnRequest(st,ACS,wayfURL.second,resource,NULL);
+    else if (!strcmp(handler->getString("wayfBinding").second,"urn:mace:shibboleth:1.0:profiles:EAuth")) {
+        // TODO: Finalize E-Auth profile URI
+        pair<bool,bool> localRelayState=m_conf->getPropertySet("Local")->getBool("localRelayState");
+        if (!localRelayState.first || !localRelayState.second)
+            throw ConfigurationException("Federal E-Authn requests cannot include relay state, so localRelayState must be enabled.");
+
+        // Here we store the state in a cookie.
+        pair<string,const char*> shib_cookie=getCookieNameProps("_shibstate_");
+        st->setCookie(shib_cookie.first,CgiParse::url_encode(resource) + shib_cookie.second);
+        return make_pair(true, st->sendRedirect(wayfURL.second));
+    }
+   
+    throw UnsupportedProfileException("Unsupported WAYF binding ($1).", params(1,handler->getString("wayfBinding").second));
+}
+
+// Handles Shib 1.x AuthnRequest profile.
+pair<bool,void*> ShibTargetPriv::ShibAuthnRequest(
+    ShibTarget* st,
+    const IPropertySet* shire,
+    const char* dest,
+    const char* target,
+    const char* providerId
+    ) const
+{
+    // Compute the ACS URL. We add the ACS location to the handler baseURL.
+    // Legacy configs will not have an ACS specified, so no suffix will be added.
+    string ACSloc=getHandlerURL(target);
+    if (shire) ACSloc+=shire->getString("Location").second;
+    
+    char timebuf[16];
+    sprintf(timebuf,"%u",time(NULL));
+    string req=string(dest) + "?shire=" + CgiParse::url_encode(ACSloc.c_str()) + "&time=" + timebuf;
+
+    // How should the resource value be preserved?
+    pair<bool,bool> localRelayState=m_conf->getPropertySet("Local")->getBool("localRelayState");
+    if (!localRelayState.first || !localRelayState.second) {
+        // The old way, just send it along.
+        req+="&target=" + CgiParse::url_encode(target);
+    }
+    else {
+        // Here we store the state in a cookie and send a fixed
+        // value to the IdP so we can recognize it on the way back.
+        pair<string,const char*> shib_cookie=getCookieNameProps("_shibstate_");
+        st->setCookie(shib_cookie.first,CgiParse::url_encode(target) + shib_cookie.second);
+        req+="&target=cookie";
+    }
+    
+    // Only omitted for 1.1 style requests.
+    if (providerId)
+        req+="&providerId=" + CgiParse::url_encode(providerId);
+
+    return make_pair(true, st->sendRedirect(req));
+}
+
+pair<bool,void*> ShibTargetPriv::doAssertionConsumer(ShibTarget* st, const IPropertySet* handler) const
+{
+    int profile=0;
+    string input,cookie,target,providerId;
+
+    // Right now, this only handles SAML 1.1.
+    pair<bool,const XMLCh*> binding=handler->getXMLString("Binding");
+    if (!binding.first || !XMLString::compareString(binding.second,SAMLBrowserProfile::BROWSER_POST)) {
+        if (strcasecmp(m_method.c_str(), "POST"))
+            throw FatalProfileException(
+                "SAML 1.1 Browser/POST handler does not support HTTP method ($1).", params(1,m_method.c_str())
+                );
+        
+        if (m_content_type.empty() || strcasecmp(m_content_type.c_str(),"application/x-www-form-urlencoded"))
+            throw FatalProfileException(
+                "Blocked invalid content-type ($1) submitted to SAML 1.1 Browser/POST handler.", params(1,m_content_type.c_str())
+                );
+        input=st->getPostData();
+        profile|=SAML11_POST;
+    }
+    else if (!XMLString::compareString(binding.second,SAMLBrowserProfile::BROWSER_ARTIFACT)) {
+        if (strcasecmp(m_method.c_str(), "GET"))
+            throw FatalProfileException(
+                "SAML 1.1 Browser/Artifact handler does not support HTTP method ($1).", params(1,m_method.c_str())
+                );
+        input=st->getArgs();
+        profile|=SAML11_ARTIFACT;
+    }
+    
+    if (input.empty())
+        throw FatalProfileException("SAML 1.1 Browser Profile handler received no data from browser.");
+            
+    pair<bool,const char*> loc=handler->getString("Location");
+    st->sessionNew(
+        profile,
+        loc.first ? m_handlerURL + loc.second : m_handlerURL,
+        input.c_str(),
+        m_remote_addr.c_str(),
+        target,
+        cookie,
+        providerId
+        );
+
+    st->log(ShibTarget::LogLevelDebug, string("profile processing succeeded, new session created (") + cookie + ")");
+
+    if (target=="default") {
+        pair<bool,const char*> homeURL=m_app->getString("homeURL");
+        target=homeURL.first ? homeURL.second : "/";
+    }
+    else if (target=="cookie") {
+        // Pull the target value from the "relay state" cookie.
+        pair<string,const char*> relay_cookie = getCookieNameProps("_shibstate_");
+        const char* relay_state = getCookie(st,relay_cookie.first);
+        if (!relay_state || !*relay_state) {
+            // No apparent relay state value to use, so fall back on the default.
+            pair<bool,const char*> homeURL=m_app->getString("homeURL");
+            target=homeURL.first ? homeURL.second : "/";
+        }
+        else {
+            char* rscopy=strdup(relay_state);
+            CgiParse::url_decode(rscopy);
+            target=rscopy;
+            free(rscopy);
+        }
+    }
+
+    // We've got a good session, set the session cookie.
+    pair<string,const char*> shib_cookie=getCookieNameProps("_shibsession_");
+    st->setCookie(shib_cookie.first, cookie + shib_cookie.second);
+
+    const IPropertySet* sessionProps=m_app->getPropertySet("Sessions");
+    pair<bool,bool> idpHistory=sessionProps->getBool("idpHistory");
+    if (!idpHistory.first || idpHistory.second) {
+        // Set an IdP history cookie locally (essentially just a CDC).
+        CommonDomainCookie cdc(getCookie(st,CommonDomainCookie::CDCName));
+
+        // Either leave in memory or set an expiration.
+        pair<bool,unsigned int> days=sessionProps->getUnsignedInt("idpHistoryDays");
+            if (!days.first || days.second==0)
+                st->setCookie(CommonDomainCookie::CDCName,string(cdc.set(providerId.c_str())) + shib_cookie.second);
+            else {
+                time_t now=time(NULL) + (days.second * 24 * 60 * 60);
+#ifdef HAVE_GMTIME_R
+                struct tm res;
+                struct tm* ptime=gmtime_r(&now,&res);
+#else
+                struct tm* ptime=gmtime(&now);
+#endif
+                char timebuf[64];
+                strftime(timebuf,64,"%a, %d %b %Y %H:%M:%S GMT",ptime);
+                st->setCookie(
+                    CommonDomainCookie::CDCName,
+                    string(cdc.set(providerId.c_str())) + shib_cookie.second + "; expires=" + timebuf
+                    );
+        }
+    }
+
+    // Now redirect to the target.
+    return pair<bool,void*>(true, st->sendRedirect(target));
+}
+
+pair<bool,void*> ShibTargetPriv::doLogout(ShibTarget* st, const IPropertySet* handler) const
+{
+    throw UnsupportedProfileException("Logout not yet supported.");
+}
+
 /*************************************************************************
  * CGI Parser implementation
  */
index c85f9eb..4ff9e06 100644 (file)
@@ -78,6 +78,7 @@
 namespace shibtarget {
   
     DECLARE_SAML_EXCEPTION(SHIBTARGET_EXPORTS,ListenerException,SAMLException);
+    DECLARE_SAML_EXCEPTION(SHIBTARGET_EXPORTS,ConfigurationException,SAMLException);
 
     // Abstract APIs for access to configuration information
     
@@ -131,6 +132,7 @@ namespace shibtarget {
     {
         virtual const char* getId() const=0;
         virtual const char* getHash() const=0;
+        
         virtual saml::Iterator<saml::SAMLAttributeDesignator*> getAttributeDesignators() const=0;
         virtual saml::Iterator<shibboleth::IAAP*> getAAPProviders() const=0;
         virtual saml::Iterator<shibboleth::IMetadata*> getMetadataProviders() const=0;
@@ -146,6 +148,17 @@ namespace shibtarget {
         // caller is given ownership of object, must use and delete within scope of config lock
         virtual saml::SAMLBrowserProfile::ArtifactMapper* getArtifactMapper() const=0;
 
+        // Used to locate a default or designated session initiator for automatic sessions
+        virtual const IPropertySet* getDefaultSessionInitiator() const=0;
+        virtual const IPropertySet* getSessionInitiatorById(const char* id) const=0;
+        
+        // Used by session initiators to get endpoint to forward to IdP/WAYF
+        virtual const IPropertySet* getDefaultAssertionConsumerService() const=0;
+        virtual const IPropertySet* getAssertionConsumerServiceByIndex(unsigned short index) const=0;
+        
+        // Used by dispatcher to locate a handler for a Shibboleth request
+        virtual const IPropertySet* getHandler(const char* path) const=0;
+
         virtual ~IApplication() {}
     };
 
@@ -397,8 +410,8 @@ namespace shibtarget {
     virtual HTAccessInfo* getAccessInfo(void);
     virtual HTGroupTable* getGroupTable(std::string &user);
 
-    // We're done.  Finish up.  Send either a result (error?) page or a redirect.
-    // If there are no headers supplied assume the content-type == text/html
+    // We're done.  Finish up.  Send specific result content or a redirect.
+    // If there are no headers supplied assume the content-type is text/html
     typedef std::pair<std::string, std::string> header_t;
     virtual void* sendPage(
         const std::string& msg,
@@ -410,11 +423,9 @@ namespace shibtarget {
       std::string m = msg;
       return sendPage(m);
     }
-
-    virtual void* sendError(const char* page, ShibMLP &mlp);
     virtual void* sendRedirect(const std::string& url)=0;
+    virtual void* sendError(const char* page, ShibMLP &mlp);
     
-
     // These next two APIs are used to obtain the module-specific "OK"
     // and "Decline" results.  OK means "we believe that this request
     // should be accepted".  Declined means "we believe that this is
@@ -449,36 +460,16 @@ namespace shibtarget {
     //   automatically call doHandlePOST() when it encounters a request for
     //   the ShireURL;  if false it will call returnOK() instead.
     //
-    std::pair<bool,void*> doCheckAuthN(bool requireSession = false, bool handleProfile = false);
-    std::pair<bool,void*> doHandleProfile();
+    std::pair<bool,void*> doCheckAuthN(bool requireSession = false, bool handler = false);
+    std::pair<bool,void*> doHandler();
     std::pair<bool,void*> doCheckAuthZ();
     std::pair<bool,void*> doExportAssertions(bool exportAssertion = false);
 
-    //**************************************************************************
-    // These APIs are for backwards-compatibility.  Hopefully they can
-    // eventually go away.
-
-    // SHIRE APIs
-
-    // Get the session cookie name and properties for the application
-    std::pair<std::string,const char*> getCookieNameProps(const char* prefix) const;
-
-    // Find the default assertion consumer service for the resource
-    const char* getShireURL(const char* resource) const;
-        
-    // Generate a Shib 1.x AuthnRequest redirect URL for the resource
-    std::string getAuthnRequest(const char* resource);
-        
-    // Process a lazy session setup request and turn it into an AuthnRequest
-    std::string getLazyAuthnRequest(const char* query_string);
-        
-  protected:
-    ShibTarget();
-
     // Currently wraps remoted interface.
     // TODO: Move this functionality behind IListener
     void sessionNew(
         int supported_profiles,
+        const std::string& recipient,
         const char* packet,
         const char* ip,
         std::string& target,
@@ -496,6 +487,11 @@ namespace shibtarget {
         saml::SAMLResponse** attr_response_post=NULL
         ) const;
 
+  protected:
+    ShibTarget();
+
+    // Internal APIs
+
     // Initialize the request from the parsed URL
     // protocol == http, https, etc
     // hostname == server name
@@ -504,14 +500,14 @@ namespace shibtarget {
     // method == GET, POST, etc.
     void init(
         ShibTargetConfig *config,
-           const char* protocol,
+        const char* protocol,
         const char* hostname,
         int port,
-           const char* uri,
+        const char* uri,
         const char* content_type,
         const char* remote_host,
-           const char* method
-       );
+        const char* method
+        );
 
   private:
     mutable ShibTargetPriv *m_priv;