Consolidated exception and status handling into a single class.
authorcantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Tue, 29 Mar 2005 02:49:19 +0000 (02:49 +0000)
committercantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Tue, 29 Mar 2005 02:49:19 +0000 (02:49 +0000)
git-svn-id: https://svn.middleware.georgetown.edu/cpp-sp/trunk@1439 cb58f699-b61c-0410-a6fe-9272a202ed29

18 files changed:
apache/mod_apache.cpp
isapi_shib/isapi_shib.cpp
shib-target/ArtifactMapper.cpp
shib-target/Makefile.am
shib-target/hresult.h [new file with mode: 0644]
shib-target/internal.h
shib-target/shib-ccache.cpp
shib-target/shib-config.cpp
shib-target/shib-mlp.cpp
shib-target/shib-rpcerror.cpp [deleted file]
shib-target/shib-rpchandle.cpp
shib-target/shib-target.cpp
shib-target/shib-target.h
shib-target/shibrpc-server.cpp
shib-target/shibrpc-xdr.c
shib-target/shibrpc.h
shib-target/shibrpc.x
shib-target/shibtarget.dsp

index 25ae2a5..a0f0a5a 100644 (file)
@@ -226,7 +226,7 @@ public:
   HTGroupTableApache(request_rec* r, const char *user, char *grpfile) {
     groups = groups_for_user(r, user, grpfile);
     if (!groups)
-      throw ShibTargetException(SHIBRPC_OK, "EEP");
+      throw ResourceAccessException("Unable to access group file ($1) for user ($2)",params(2,grpfile,user));
   }
   ~HTGroupTableApache() {}
   bool lookup(const char *entry) { return (ap_table_get(groups, entry)!=NULL); }
@@ -273,12 +273,11 @@ public:
   virtual string getPostData(void) {
     // Read the posted data
     if (ap_setup_client_block(m_req, REQUEST_CHUNKED_ERROR))
-      throw ShibTargetException(SHIBRPC_OK, "CGI setup_client_block failed");
+        throw FatalProfileException("Apache function (setup_client_block) failed while reading profile submission.");
     if (!ap_should_client_block(m_req))
-      throw ShibTargetException(SHIBRPC_OK, "CGI should_client_block failed");
+        throw FatalProfileException("Apache function (should_client_block) failed while reading profile submission.");
     if (m_req->remaining > 1024*1024)
-      throw ShibTargetException (SHIBRPC_OK, "CGI length too long...");
-
+        throw FatalProfileException("Blocked too-large a submission to profile endpoint.");
     string cgistr;
     char buff[HUGE_STRING_LEN];
     ap_hard_timeout("[mod_shib] getPostData", m_req);
index e12c1cd..59fbbe5 100644 (file)
@@ -1066,8 +1066,7 @@ public:
   }
   virtual string getPostData(void) {
     if (m_lpECB->cbTotalBytes > 1024*1024) // 1MB?
-      throw ShibTargetException(SHIBRPC_OK,
-                               "blocked too-large a post to SHIRE POST processor");
+      throw FatalProfileException("Blocked too-large a submission to profile endpoint.");
     else if (m_lpECB->cbTotalBytes != m_lpECB->cbAvailable) {
       string cgistr;
       char buf[8192];
@@ -1076,8 +1075,7 @@ public:
        DWORD buflen=8192;
        BOOL ret = m_lpECB->ReadClient(m_lpECB->ConnID, buf, &buflen);
        if (!ret || !buflen)
-         throw ShibTargetException(SHIBRPC_OK,
-                                   "error reading POST data from browser");
+         throw FatalProfileException("Error reading profile submission from browser.");
        cgistr.append(buf, buflen);
        datalen-=buflen;
       }
index 8c1096f..8e0a18f 100644 (file)
@@ -79,13 +79,11 @@ SAMLBrowserProfile::ArtifactMapper::ArtifactMapperResponse STArtifactMapper::map
         throw MetadataException("ArtifactMapper::map() metadata lookup failed, unable to determine artifact issuer");
     }
     
-    if (log.isInfoEnabled()) {
-        auto_ptr_char issuer(entity->getId());
-        log.info("lookup succeeded, artifact issued by (%s)", issuer.get());
-    }
-    
     SAMLBrowserProfile::ArtifactMapper::ArtifactMapperResponse amr;
-
+    auto_ptr_char issuer(entity->getId());
+    log.info("lookup succeeded, artifact issued by (%s)", issuer.get());
+    amr.source=issuer.get();
+    
     const IPropertySet* credUse=m_app->getCredentialUse(entity);
 
     // Depends on type of artifact.
@@ -175,5 +173,7 @@ SAMLBrowserProfile::ArtifactMapper::ArtifactMapperResponse STArtifactMapper::map
     }
     
     log.error("unable to locate acceptable binding endpoint to resolve artifact");
-    throw MetadataException("ArtifactMapper::map() unable to locate acceptable binding endpoint to resolve artifact");
+    MetadataException ex("Unable to locate acceptable binding endpoint to resolve artifact.");
+    annotateException(ex,entity,false);
+    throw ex;
 }
index 6856553..8235d49 100644 (file)
@@ -14,7 +14,7 @@ AM_CXXFLAGS = -I${top_srcdir}/oncrpc
 endif
 
 libshib_targetdir = $(includedir)/shib-target
-libshib_target_HEADERS = shib-target.h shibrpc.h shib-paths.h
+libshib_target_HEADERS = shib-target.h shibrpc.h shib-paths.h hresult.h
 noinst_HEADERS = internal.h
 
 libshib_target_la_SOURCES = \
diff --git a/shib-target/hresult.h b/shib-target/hresult.h
new file mode 100644 (file)
index 0000000..7a00831
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * The Shibboleth License, Version 1.
+ * Copyright (c) 2002
+ * University Corporation for Advanced Internet Development, Inc.
+ * All rights reserved
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution, if any, must include
+ * the following acknowledgment: "This product includes software developed by
+ * the University Corporation for Advanced Internet Development
+ * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement
+ * may appear in the software itself, if and wherever such third-party
+ * acknowledgments normally appear.
+ *
+ * Neither the name of Shibboleth nor the names of its contributors, nor
+ * Internet2, nor the University Corporation for Advanced Internet Development,
+ * Inc., nor UCAID may be used to endorse or promote products derived from this
+ * software without specific prior written permission. For written permission,
+ * please contact shibboleth@shibboleth.org
+ *
+ * Products derived from this software may not be called Shibboleth, Internet2,
+ * UCAID, or the University Corporation for Advanced Internet Development, nor
+ * may Shibboleth appear in their name, without prior written permission of the
+ * University Corporation for Advanced Internet Development.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK
+ * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY
+ * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* 
+ * hresult.h - Code definitions
+= */
+
+#ifndef __shibtargethresult_h__
+#define __shibtargethresult_h__
+
+#include <shib/hresult.h>
+
+/* Codes from 0xA000 - 0xAFFF in FACILITY_ITF are reserved for the Shibboleth SP */
+
+#define SHIBSP_E_FIRST MAKE_HRESULT(SEVERITY_ERROR,FACILITY_ITF,SHIB_E_LAST + 0x0001)
+#define SHIBSP_E_LAST MAKE_HRESULT(SEVERITY_ERROR,FACILITY_ITF,SHIB_E_LAST + 0x1000)
+
+#define SHIBSP_S_FIRST MAKE_HRESULT(SEVERITY_SUCCESS,FACILITY_ITF,SHIB_S_LAST + 0x0001)
+#define SHIBSP_S_LAST MAKE_HRESULT(SEVERITY_SUCCESS,FACILITY_ITF,SHIB_S_LAST + 0x1000
+
+/* Specific code definitions */
+
+#define SHIBSP_E_UNSPECIFIED                (SHIBSP_E_FIRST + 0L)
+
+#define SESSION_E_ADDRESSMISMATCH           (SHIBSP_E_FIRST + 1L)
+#define SESSION_E_EXPIRED                   (SHIBSP_E_FIRST + 2L)
+
+#endif
index 9544252..46f2996 100644 (file)
@@ -71,6 +71,7 @@
 #endif
 
 #include "shib-target.h"
+#include "hresult.h"
 
 #include <log4cpp/Category.hh>
 #include <log4cpp/FixedContextCategory.hh>
@@ -122,7 +123,7 @@ namespace shibtarget {
         RPC();
         ~RPC() {delete m_handle;}
         RPCHandle* operator->() {return m_handle;}
-        void pool() {m_pool.put(m_handle); m_handle=NULL;}
+        void pool() {if (m_handle) m_pool.put(m_handle); m_handle=NULL;}
     
     private:
         RPCHandlePool& m_pool;
index 3589cde..7954e12 100644 (file)
@@ -666,7 +666,7 @@ void InternalCCacheEntry::populate()
   catch (...) {
     if (m_cache->m_propagateErrors)
         throw;
-    log->warn("suppressed exception caught while trying to fetch attributes");
+    log->warn("suppressed unknown exception caught while trying to fetch attributes");
   }
 }
 
@@ -692,12 +692,12 @@ pair<SAMLResponse*,SAMLResponse*> InternalCCacheEntry::getNewResponse()
     const IApplication* application=conf->getApplication(m_application_id.c_str());
     if (!application) {
         log->crit("unable to locate application for session, deleted?");
-        throw ShibTargetException(SHIBRPC_INTERNAL_ERROR,"Unable to locate application for session, deleted?");
+        throw SAMLException("Unable to locate application for session, deleted?");
     }
     pair<bool,const XMLCh*> providerID=application->getXMLString("providerId");
     if (!providerID.first) {
         log->crit("unable to determine ProviderID for application, not set?");
-        throw ShibTargetException(SHIBRPC_INTERNAL_ERROR,"Unable to determine ProviderID for application, not set?");
+        throw SAMLException("Unable to determine ProviderID for application, not set?");
     }
 
     // Try this request.
@@ -705,14 +705,15 @@ pair<SAMLResponse*,SAMLResponse*> InternalCCacheEntry::getNewResponse()
     const IEntityDescriptor* site=m.lookup(m_provider_id.c_str());
     if (!site) {
         log->error("unable to locate identity provider's metadata during attribute query");
-        throw ShibTargetException(SHIBRPC_INTERNAL_ERROR,"Unable to locate identity provider's metadata during attribute query.");
+        throw MetadataException("Unable to locate identity provider's metadata during attribute query.");
     }
 
     // Try to locate an AA role.
     const IAttributeAuthorityDescriptor* AA=site->getAttributeAuthorityDescriptor(saml::XML::SAML11_PROTOCOL_ENUM);
     if (!AA) {
         log->error("unable to locate metadata for identity provider's Attribute Authority");
-        throw ShibTargetException(SHIBRPC_INTERNAL_ERROR,"Unable to locate metadata for identity provider's Attribute Authority.",site);
+        MetadataException ex("Unable to locate metadata for identity provider's Attribute Authority.");
+        annotateException(ex,site);
     }
 
     // Get protocol signing policy.
@@ -788,15 +789,13 @@ pair<SAMLResponse*,SAMLResponse*> InternalCCacheEntry::getNewResponse()
     }
     catch (SAMLException& e) {
         log->error("caught SAML exception during query to AA: %s", e.what());
-        if (typeid(e)==typeid(InvalidHandleException))
-            throw;
-        ostringstream os;
-        os << e;
-        throw ShibTargetException(SHIBRPC_SAML_EXCEPTION, os.str().c_str(), AA);
+        annotateException(e,AA);
     }
     
     log->error("no response obtained");
-    throw ShibTargetException(SHIBRPC_INTERNAL_ERROR,"Unable to obtain attributes from user's identity provider.",AA);
+    SAMLException ex("Unable to obtain attributes from user's identity provider.");
+    annotateException(ex,AA,false);
+    throw ex;
 }
 
 SAMLResponse* InternalCCacheEntry::filter(SAMLResponse* r, const IApplication* application, const IRoleDescriptor* source)
index 3ad3e89..7f46801 100644 (file)
@@ -87,6 +87,8 @@ PlugManager::Factory MemoryCacheFactory;
 PlugManager::Factory XMLRequestMapFactory;
 //PlugManager::Factory htaccessFactory;
 
+SAML_EXCEPTION_FACTORY(ListenerException);
+
 ShibTargetConfig& ShibTargetConfig::getConfig()
 {
     return g_Config;
@@ -162,6 +164,7 @@ bool STConfig::init(const char* schemadir, const char* config)
 
     try {
         // Register plugin types.
+        REGISTER_EXCEPTION_FACTORY(ListenerException);
 #ifndef WIN32
         samlConf.getPlugMgr().regFactory(shibtarget::XML::UnixListenerType,&UnixListenerFactory);
 #endif
index 6d06e83..a774357 100644 (file)
@@ -286,14 +286,16 @@ const char* ShibMLP::run(istream& is, const IPropertySet* props, std::string* ou
   return run(str,props,output);
 }
 
-void ShibMLP::insert (RPCError& e)
+void ShibMLP::insert(SAMLException& e)
 {
-    insert ("errorType", e.getType() ? e.getType() : "Unknown Type");
-    insert ("errorText", e.getText() ? e.getText() : "No Message");
-    insert ("errorDesc", e.getDesc() ? e.getDesc() : "No Description");
-    insert ("originErrorURL", e.getErrorURL() ? e.getErrorURL() : "No Error URL");
-    insert ("originContactName", e.getContactName() ? e.getContactName() : "No Contact Name");
-    insert ("originContactEmail", e.getContactEmail() ? e.getContactEmail() : "No Contact Email");
+    insert("errorType", e.classname());
+    if (typeid(e)==typeid(ContentTypeException))
+        insert("errorText", "A problem was detected with your identity provider's software configuration.");
+    else
+        insert("errorText", e.getMessage() ? e.getMessage() : "No Message");
+    insert("originErrorURL", e.getProperty("errorURL") ? e.getProperty("errorURL") : "No Error URL");
+    insert("originContactName", e.getProperty("contactName") ? e.getProperty("contactName") : "No Contact Name");
+    insert("originContactEmail", e.getProperty("contactEmail") ? e.getProperty("contactEmail") : "No Contact Email");
 }
 
 void ShibMLP::insert (const std::string& key, const std::string& value)
diff --git a/shib-target/shib-rpcerror.cpp b/shib-target/shib-rpcerror.cpp
deleted file mode 100644 (file)
index 7478fb0..0000000
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * The Shibboleth License, Version 1.
- * Copyright (c) 2002
- * University Corporation for Advanced Internet Development, Inc.
- * All rights reserved
- *
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution, if any, must include
- * the following acknowledgment: "This product includes software developed by
- * the University Corporation for Advanced Internet Development
- * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement
- * may appear in the software itself, if and wherever such third-party
- * acknowledgments normally appear.
- *
- * Neither the name of Shibboleth nor the names of its contributors, nor
- * Internet2, nor the University Corporation for Advanced Internet Development,
- * Inc., nor UCAID may be used to endorse or promote products derived from this
- * software without specific prior written permission. For written permission,
- * please contact shibboleth@shibboleth.org
- *
- * Products derived from this software may not be called Shibboleth, Internet2,
- * UCAID, or the University Corporation for Advanced Internet Development, nor
- * may Shibboleth appear in their name, without prior written permission of the
- * University Corporation for Advanced Internet Development.
- *
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
- * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK
- * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY
- * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * shib-rpcerror.cpp -- RPC Error class
- *
- * Created by: Derek Atkins <derek@ihtfp.com>
- *
- * $Id$
- */
-
-#include "internal.h"
-
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
-#include <stdexcept>
-#include <sstream>
-#include <typeinfo>
-#include <log4cpp/Category.hh>
-
-using namespace std;
-using namespace log4cpp;
-using namespace saml;
-using namespace shibboleth;
-using namespace shibtarget;
-
-ShibTargetException::ShibTargetException(ShibRpcStatus code, const char* msg, const IEntityDescriptor* provider) : m_code(code)
-{
-    if (msg) m_msg=msg;
-    if (provider) {
-        auto_ptr_char id(provider->getId());
-        m_providerId=id.get();
-        Iterator<const IRoleDescriptor*> roles=provider->getRoleDescriptors();
-        while (roles.hasNext()) {
-            const IRoleDescriptor* role=roles.next();
-            if (role->isValid()) {
-                const char* temp=role->getErrorURL();
-                if (temp) {
-                    m_errorURL=temp;
-                    break;
-                }
-            }
-        }
-
-        Iterator<const IContactPerson*> i=provider->getContactPersons();
-        while (i.hasNext()) {
-            const IContactPerson* c=i.next();
-            if ((c->getType()==IContactPerson::technical || c->getType()==IContactPerson::support)) {
-                const char* fname=c->getGivenName();
-                const char* lname=c->getSurName();
-                if (fname && lname)
-                    m_contact=string(fname) + ' ' + lname;
-                else if (fname)
-                    m_contact=fname;
-                else if (lname)
-                    m_contact=lname;
-                Iterator<string> emails=c->getEmailAddresses();
-                if (emails.hasNext())
-                    m_email=emails.next();
-                return;
-            }
-        }
-    }
-}
-
-ShibTargetException::ShibTargetException(ShibRpcStatus code, const char* msg, const IRoleDescriptor* role) : m_code(code)
-{
-    if (msg) m_msg=msg;
-    if (role) {
-        auto_ptr_char id(role->getEntityDescriptor()->getId());
-        m_providerId=id.get();
-
-        const char* temp=role->getErrorURL();
-        if (temp)
-            m_errorURL=temp;
-
-        Iterator<const IContactPerson*> i=role->getContactPersons();
-        while (i.hasNext()) {
-            const IContactPerson* c=i.next();
-            if ((c->getType()==IContactPerson::technical || c->getType()==IContactPerson::support)) {
-                const char* fname=c->getGivenName();
-                const char* lname=c->getSurName();
-                if (fname && lname)
-                    m_contact=string(fname) + ' ' + lname;
-                else if (fname)
-                    m_contact=fname;
-                else if (lname)
-                    m_contact=lname;
-                Iterator<string> emails=c->getEmailAddresses();
-                if (emails.hasNext())
-                    m_email=emails.next();
-                return;
-            }
-        }
-    }
-}
-
-class shibtarget::RPCErrorPriv {
-public:
-  RPCErrorPriv(
-    int stat=0,
-    const char* msg=NULL,
-    const char* provider=NULL,
-    const char* url=NULL,
-    const char* contact=NULL,
-    const char* email=NULL
-    );
-  ~RPCErrorPriv();
-
-  int status;
-  string error_msg,m_provider,m_url,m_contact,m_email;
-  SAMLException* except;
-};
-
-RPCErrorPriv::RPCErrorPriv(
-    int stat, const char* msg, const char* provider, const char* url, const char* contact, const char* email
-    ) : status(stat), except(NULL)
-{
-  log4cpp::Category& log = log4cpp::Category::getInstance("shibtarget.RPCErrorPriv");
-
-  if (provider)
-    m_provider=provider;
-  if (url)
-    m_url=url;
-  if (contact)
-    m_contact=contact;
-  if (email)
-    m_email=email;
-
-  if (status == SHIBRPC_SAML_EXCEPTION) {
-    istringstream estr(msg);
-    try { 
-      except = NULL;
-      except = SAMLException::getInstance(estr);
-    }
-    catch (SAMLException& e) {
-      log.error("Caught SAML Exception while building the SAMLException: %s", e.what());
-      log.error("XML: %s", msg);
-    }
-    catch (XMLException& e) {
-      log.error("Caught XML Exception building SAMLException: %s", e.getMessage());
-      log.error("XML: %s", msg);
-    }
-    catch (...) {
-      log.error("Caught exception building SAMLException!");
-      log.error("XML: %s", msg);
-    }
-    if (dynamic_cast<ContentTypeException*>(except))
-        error_msg =
-          "We were unable to contact your identity provider and cannot grant "
-          "access at this time. Please contact your provider's help desk or "
-          "administrator so that the appropriate steps can be taken.  "
-          "Be sure to describe what you're trying to access and useful "
-          "context like the current time.";
-    else if (except)
-        error_msg = except->what();
-    else if (msg)
-        error_msg = msg;
-  }
-  else if (msg)
-    error_msg = msg;
-}
-
-RPCErrorPriv::~RPCErrorPriv()
-{
-  if (except)
-    delete except;
-}
-
-RPCError::RPCError() : m_priv(new RPCErrorPriv()) {}
-
-RPCError::RPCError(ShibRpcError* e)
-{
-    if (!e || !e->status)
-        m_priv=new RPCErrorPriv();
-    m_priv=new RPCErrorPriv(
-        e->status,
-        e->ShibRpcError_u.e.error,
-        e->ShibRpcError_u.e.provider,
-        e->ShibRpcError_u.e.url,
-        e->ShibRpcError_u.e.contact,
-        e->ShibRpcError_u.e.email
-        );
-}
-
-RPCError::RPCError(int s, const char* st) : m_priv(new RPCErrorPriv(s,st)) {}
-
-RPCError::RPCError(ShibTargetException& exc)
-    : m_priv(new RPCErrorPriv(exc.which(),exc.what(),exc.syswho(),exc.where(),exc.who(),exc.how())) {}
-
-RPCError::~RPCError()
-{
-  delete m_priv;
-}
-
-bool RPCError::isError() { return (m_priv->status != 0); }
-
-bool RPCError::isRetryable()
-{
-  switch (m_priv->status) {
-  case SHIBRPC_NO_SESSION:
-  case SHIBRPC_SESSION_EXPIRED:
-    return true;
-
-  case SHIBRPC_SAML_EXCEPTION:
-    if (m_priv->except && dynamic_cast<RetryableProfileException*>(m_priv->except))
-        return true;
-
-    // FALLTHROUGH
-    default:
-        return false;
-  }
-}
-
-const char* RPCError::getType()
-{
-  switch (m_priv->status) {
-  case SHIBRPC_OK:                  return "No Error";
-  case SHIBRPC_UNKNOWN_ERROR:       return "Unknown error";
-  case SHIBRPC_INTERNAL_ERROR:      return "Internal Error";
-  case SHIBRPC_XML_EXCEPTION:       return "Xerces XML Exception";
-  case SHIBRPC_SAX_EXCEPTION:       return "Xerces SAX Exception";
-  case SHIBRPC_SAML_EXCEPTION:      return m_priv->except->classname();
-
-  case SHIBRPC_NO_SESSION:          return "No Session";
-  case SHIBRPC_SESSION_EXPIRED:     return "Session Expired";
-  case SHIBRPC_IPADDR_MISMATCH:     return "IP Address Mismatch";
-
-  case SHIBRPC_IPADDR_MISSING:      return "IP Address Missing";
-  case SHIBRPC_RESPONSE_MISSING:    return "SAML Response Missing";
-  case SHIBRPC_ASSERTION_REPLAYED:  return "SAML Assertion Replayed";
-  default:                          return "Unknown Shibboleth RPC error";
-  }
-}
-
-const char* RPCError::getText()
-{
-  return m_priv->error_msg.c_str();
-}
-
-const char* RPCError::getDesc()
-{
-  if (m_priv->except) {
-    Iterator<saml::QName> i=m_priv->except->getCodes();
-    if (i.hasNext() && XMLString::compareString(L(Responder),i.next().getLocalName()))
-      return "An error occurred within the target system while processing your request";
-    else
-      return "An error occurred at your identity provider while processing your request";
-  }
-  else
-    return "An error occurred while processing your request";
-}
-
-int RPCError::getCode() { return m_priv->status; }
-
-const char* RPCError::getProviderId() { return m_priv->m_provider.c_str(); }
-
-const char* RPCError::getErrorURL() { return m_priv->m_url.c_str(); }
-
-const char* RPCError::getContactName() { return m_priv->m_contact.c_str(); }
-
-const char* RPCError::getContactEmail() { return m_priv->m_email.c_str(); }
index 0b9ba12..28108ce 100644 (file)
@@ -100,14 +100,15 @@ void RPCHandle::disconnect()
 
 CLIENT* RPCHandle::connect()
 {
+#ifdef _DEBUG
     saml::NDC ndc("connect");
-
+#endif
     if (m_clnt) {
-        log->debug ("returning existing connection: %p -> %p", this, m_clnt);
+        log->debug("returning existing connection: %p -> %p", this, m_clnt);
         return m_clnt;
     }
 
-    log->debug("trying to connect to SHAR");
+    log->debug("trying to connect to listener");
 
     IListener::ShibSocket sock;
     IConfig* conf=ShibTargetConfig::getConfig().getINI();
@@ -115,7 +116,7 @@ CLIENT* RPCHandle::connect()
     const IListener* listener=conf->getListener();
     if (!listener->create(sock)) {
         log->error("cannot create socket");
-        throw ShibTargetException(SHIBRPC_UNKNOWN_ERROR, "Cannot create socket");
+        throw ListenerException("Cannot create socket");
     }
 
     bool connected = false;
@@ -127,20 +128,21 @@ CLIENT* RPCHandle::connect()
             break;
         }
     
-        log->warn ("cannot connect %p to SHAR... %s", this, (i > 0 ? "retrying" : ""));
+        log->warn("cannot connect %p to listener...%s", this, (i > 0 ? "retrying" : ""));
 
-        if (i)
+        if (i) {
 #ifdef WIN32
             Sleep(2000*(num_tries-i));
 #else
             sleep(2*(num_tries-i));
 #endif
+        }
     }
 
     if (!connected) {
-        log->crit("SHAR Unavailable..  Failing.");
+        log->crit("listener unavailable, failing");
         listener->close(sock);
-        throw ShibTargetException(SHIBRPC_UNKNOWN_ERROR, "Cannot connect to SHAR process, target site adminstrator should be notified");
+        throw ListenerException("Cannot connect to listener process, a site adminstrator should be notified.");
     }
 
     CLIENT *clnt = listener->getClientHandle(sock, SHIBRPC_PROG, SHIBRPC_VERS_2);
@@ -148,7 +150,7 @@ CLIENT* RPCHandle::connect()
         const char* rpcerror = clnt_spcreateerror("RPCHandle::connect");
         log->crit("RPC failed for %p: %s", this, rpcerror);
         listener->close(sock);
-        throw ShibTargetException(SHIBRPC_UNKNOWN_ERROR, rpcerror);
+        throw ListenerException(rpcerror);
     }
 
     // Set the RPC timeout to a fairly high value...
index 8846e32..7b94ef9 100644 (file)
@@ -163,10 +163,16 @@ ShibTarget::~ShibTarget(void)
   if (m_priv) delete m_priv;
 }
 
-void ShibTarget::init(ShibTargetConfig *config,
-                     string protocol, string hostname, int port,
-                     string uri, string content_type, string remote_host,
-                     string method)
+void ShibTarget::init(
+    ShibTargetConfig *config,
+    string protocol,
+    string hostname,
+    int port,
+    string uri,
+    string content_type,
+    string remote_host,
+    string method
+    )
 {
 #ifdef _DEBUG
   saml::NDC ndc("ShibTarget::init");
@@ -193,286 +199,270 @@ pair<bool,void*>
 ShibTarget::doCheckAuthN(bool requireSessionFlag, bool handleProfile)
 {
 #ifdef _DEBUG
-  saml::NDC ndc("ShibTarget::doCheckAuthN");
+    saml::NDC ndc("ShibTarget::doCheckAuthN");
 #endif
 
-  const char *targetURL = NULL;
-  const char *procState = "Process Initialization Error";
-  ShibMLP mlp;
+    const char *targetURL = NULL;
+    const char *procState = "Request Setup Error";
+    ShibMLP mlp;
 
-  try {
-    if (! m_priv->m_app)
-      throw ShibTargetException(SHIBRPC_OK, "ShibTarget Uninitialized.  Application did not supply request information.");
-
-    targetURL = m_priv->m_url.c_str();
-    const char *shireURL = getShireURL(targetURL);
-    if (! shireURL)
-      throw ShibTargetException(SHIBRPC_OK, "Cannot map target URL to Shire URL.  Check configuration");
+    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);
+        if (!shireURL)
+            throw SAMLException("Cannot determine assertion consumer service from resource URL, check configuration.");
+
+        if (strstr(targetURL,shireURL)) {
+            if (handleProfile)
+                return doHandleProfile();
+            else
+                return pair<bool,void*>(true, returnOK());
+        }
 
-    if (strstr(targetURL,shireURL)) {
-      if (handleProfile)
-        return doHandleProfile();
-      else
-        return pair<bool,void*>(true, returnOK());
-    }
+        string auth_type = getAuthType();
+        if (strcasecmp(auth_type.c_str(),"shibboleth"))
+            return pair<bool,void*>(true,returnDecline());
 
-    string auth_type = getAuthType();
-    if (strcasecmp(auth_type.c_str(),"shibboleth"))
-      return pair<bool,void*>(true,returnDecline());
+        pair<bool,bool> requireSession = m_priv->m_settings.first->getBool("requireSession");
+        if (!requireSession.first || !requireSession.second) {
+            // Web server might override.
+            if (requireSessionFlag)
+                requireSession.second=true;
+        }
 
-    pair<bool,bool> requireSession =
-      m_priv->m_settings.first->getBool("requireSession");
-    if (!requireSession.first || !requireSession.second)
-      if (requireSessionFlag)
-       requireSession.second=true;
+        const char* session_id = m_priv->getSessionId(this);
+        if (!session_id || !*session_id) {
+            // No session.  Maybe that's acceptable?
+            if (!requireSession.second)
+                return pair<bool,void*>(true,returnOK());
 
-    const char* session_id = m_priv->getSessionId(this);
-    if (!session_id || !*session_id) {
-      // No session.  Maybe that's acceptable?
+            // No cookie, but we require a session.  Generate an AuthnRequest.
+            return pair<bool,void*>(true,sendRedirect(getAuthnRequest(targetURL)));
+        }
 
-      if (!requireSession.second)
-        return pair<bool,void*>(true,returnOK());
+        procState = "Session Processing Error";
+        try {
+            // Localized exception throw if the session isn't valid.
+            sessionGet(
+                session_id,
+                m_priv->m_remote_addr.c_str(),
+                m_priv->m_sso_profile,
+                m_priv->m_provider_id,
+                &m_priv->m_sso_statement,
+                &m_priv->m_pre_response,
+                &m_priv->m_post_response
+                );
+        }
+        catch (SAMLException& e) {
+            // If no session is required, bail now.
+            if (!requireSession.second)
+                // Has to be OK because DECLINED will just cause Apache
+                // to fail when it can't locate anything to process the
+                // AuthType.  No session plus requireSession false means
+                // do not authenticate the user at this time.
+                return 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)));
+            }
+            throw;    // send it to the outer handler
+        }
 
-      // No cookie, but we require a session.  Generate an AuthnRequest.
-      return pair<bool,void*>(true,sendRedirect(getAuthnRequest(targetURL)));
+        // We're done.  Everything is okay.  Nothing to report.  Nothing to do..
+        // Let the caller decide how to proceed.
+        log(LogLevelInfo, "doCheckAuthN succeeded");
+        return pair<bool,void*>(false,NULL);
     }
-
-    procState = "Session Processing Error";
-    auto_ptr<RPCError> status(
-        sessionGet(
-            session_id,
-            m_priv->m_remote_addr.c_str(),
-            m_priv->m_sso_profile,
-            m_priv->m_provider_id,
-            &m_priv->m_sso_statement,
-            &m_priv->m_pre_response,
-            &m_priv->m_post_response
-            )
-         );
-
-    if (status->isError()) {
-
-      // If no session is required, bail now.
-      if (!requireSession.second)
-        return pair<bool,void*>(true, returnOK());
-                   // XXX: Or should this be DECLINED?
-                   // Has to be OK because DECLINED will just cause Apache
-                   // to fail when it can't locate anything to process the
-                   // AuthType.  No session plus requireSession false means
-                   // do not authenticate the user at this time.
-      else if (status->isRetryable()) {
-        // Session is invalid but we can retry the auth -- generate an AuthnRequest
-        return pair<bool,void*>(true,sendRedirect(getAuthnRequest(targetURL)));
-
-      } else {
-        string er = "Unretryable error: " ;
-        er += status->getText();
-        log(LogLevelError, er);
-        mlp.insert(*status);
-        goto out;
-      }
+    catch (SAMLException& e) {
+        mlp.insert(e);
     }
-
-    // We're done.  Everything is okay.  Nothing to report.  Nothing to do..
-    // Let the caller decide how to proceed.
-    log(LogLevelInfo, "doCheckAuthN Succeeded\n");
-    return pair<bool,void*>(false,NULL);
-
-  }
-  catch (ShibTargetException &e) {
-    mlp.insert("errorText", e.what());
-  }
 #ifndef _DEBUG
-  catch (...) {
-    mlp.insert("errorText", "Unexpected Exception");
-  }
+    catch (...) {
+        mlp.insert("errorText", "Caught an unknown exception.");
+    }
 #endif
 
-  // If we get here then we've got an error.
-  mlp.insert("errorType", procState);
-  mlp.insert("errorDesc", "An error occurred while processing your request.");
+    // If we get here then we've got an error.
+    mlp.insert("errorType", procState);
+    if (targetURL)
+        mlp.insert("requestURL", targetURL);
 
- out:
-  if (targetURL)
-    mlp.insert("requestURL", targetURL);
-
-  return pair<bool,void*>(true,m_priv->sendError(this, "session", mlp));
+    return pair<bool,void*>(true,m_priv->sendError(this, "session", mlp));
 }
 
 pair<bool,void*>
 ShibTarget::doHandleProfile(void)
 {
 #ifdef _DEBUG
-  saml::NDC ndc("ShibTarget::doHandleProfile");
+    saml::NDC ndc("ShibTarget::doHandleProfile");
 #endif
 
-  const char *targetURL = NULL;
-  const char *procState = "Session Creation Service Error";
-  ShibMLP mlp;
-
-  try {
-    if (! m_priv->m_app)
-      throw ShibTargetException(SHIBRPC_OK, "ShibTarget Uninitialized.  Application did not supply request information.");
+    const char *targetURL = NULL;
+    const char *procState = "Session Creation Service Error";
+    ShibMLP mlp;
 
-    targetURL = m_priv->m_url.c_str();
-    const char *shireURL = getShireURL(targetURL);
+    try {
+        if (!m_priv->m_app)
+            throw SAMLException("System uninitialized, application did not supply request information.");
 
-    if (!shireURL)
-      throw ShibTargetException(SHIBRPC_OK, "doHandleProfile() unable to map request to a proper shireURL setting.  Check Configuration.");
+        targetURL = m_priv->m_url.c_str();
+        const char* shireURL = getShireURL(targetURL);
 
+        if (!shireURL)
+            throw SAMLException("Cannot determine assertion consumer service, check configuration.");
 
-    // Make sure we only process the SHIRE requests.
-    if (!strstr(targetURL, shireURL))
-      return pair<bool,void*>(true, returnDecline());
+        // Make sure we only process the SHIRE requests.
+        if (!strstr(targetURL, shireURL))
+            return pair<bool,void*>(true, returnDecline());
 
-    const IPropertySet* sessionProps=m_priv->m_app->getPropertySet("Sessions");
-    if (!sessionProps)
-      throw ShibTargetException(SHIBRPC_OK, "doHandleProfile() unable to map request to application session settings.  Check configuration");
+        const IPropertySet* sessionProps=m_priv->m_app->getPropertySet("Sessions");
+        if (!sessionProps)
+            throw SAMLException("Unable to map request to application session settings, check configuration.");
 
-    // Process SHIRE request
+        // Process incoming request.
+        pair<bool,bool> shireSSL=sessionProps->getBool("shireSSL");
       
-    pair<bool,bool> shireSSL=sessionProps->getBool("shireSSL");
-      
-    // Make sure this is SSL, if it should be
-    if ((!shireSSL.first || shireSSL.second) && m_priv->m_protocol == "https")
-      throw ShibTargetException(SHIBRPC_OK, "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")) {
-            string er = string("blocked invalid POST content-type to session creation service: ") + m_priv->m_content_type;
-            throw ShibTargetException(SHIBRPC_OK, er.c_str());
+        // 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)
+                    );
+            }
+            // Read the POST Data
+            cgistr = getPostData();
         }
-        // Read the POST Data
-        cgistr = getPostData();
-    }
        
-    // process the submission
-    string cookie,target;
-    auto_ptr<RPCError> status(
-        sessionNew(
-            SAML_11_POST | SAML_11_ARTIFACT,
-            cgistr.c_str(),
-            m_priv->m_remote_addr.c_str(),
-            cookie,
-            target
-            )
-        );
-
-    if (status->isError()) {
-      char buf[25];
-      sprintf(buf, "(%d): ", status->getCode());
-      string er = string("doHandleProfile() profile processing failed ") + buf + status->getText();
-      log(LogLevelError, er);
-
-      if (status->isRetryable()) {
-        return pair<bool,void*>(true, sendRedirect(getAuthnRequest(target.c_str())));
-      }
-
-      // return this error to the user.
-      mlp.insert(*status);
-      goto out;
-    }
+        // Process the submission
+        string cookie,target;
+        try {
+            sessionNew(
+                SAML11_POST | SAML11_ARTIFACT,
+                cgistr.c_str(),
+                m_priv->m_remote_addr.c_str(),
+                cookie,
+                target
+                );
+        }
+        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())));
+            }
+            throw;    // send it to the outer handler
+        }
 
-    log(LogLevelDebug, string("doHandleProfile() profile processing succeeded, new session(") + cookie + ")");
+        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=="42") {
-        // Pull the target value from the "relay state" cookie.
-        const char* relay_state = m_priv->getRelayState(this);
-        if (!relay_state || !*relay_state) {
-            // No apparent relay state value to use, so fall back on the default.
+        if (target=="default") {
             pair<bool,const char*> homeURL=m_priv->m_app->getString("homeURL");
             target=homeURL.first ? homeURL.second : "/";
         }
-        else {
-            CgiParse::url_decode((char*)relay_state);
-            target=relay_state;
+        else if (target=="cookie") {
+            // Pull the target value from the "relay state" cookie.
+            const char* relay_state = m_priv->getRelayState(this);
+            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 {
+                CgiParse::url_decode((char*)relay_state);
+                target=relay_state;
+            }
         }
+    
+        // We've got a good session, set the cookie...
+        pair<string,const char*> shib_cookie=getCookieNameProps("_shibsession_");
+        cookie += shib_cookie.second;
+        setCookie(shib_cookie.first, cookie);
+    
+        // ... and redirect to the target
+        return pair<bool,void*>(true, sendRedirect(target));
+    }
+    catch (SAMLException& e) {
+        mlp.insert(e);
     }
-
-    // We've got a good session, set the cookie...
-    pair<string,const char*> shib_cookie=getCookieNameProps("_shibsession_");
-    cookie += shib_cookie.second;
-    setCookie(shib_cookie.first, cookie);
-
-    // ... and redirect to the target
-    return pair<bool,void*>(true, sendRedirect(target));
-
-  }
-  catch (ShibTargetException &e) {
-    mlp.insert("errorText", e.what());
-  }
 #ifndef _DEBUG
-  catch (...) {
-    mlp.insert("errorText", "Unexpected Exception");
-  }
+    catch (...) {
+        mlp.insert("errorText", "Caught an unknown exception.");
+    }
 #endif
 
-  // If we get here then we've got an error.
-  mlp.insert("errorType", procState);
-  mlp.insert("errorDesc", "An error occurred while processing your request.");
+    // If we get here then we've got an error.
+    mlp.insert("errorType", procState);
 
- out:
-  if (targetURL)
-    mlp.insert("requestURL", targetURL);
+    if (targetURL)
+        mlp.insert("requestURL", targetURL);
 
-  return pair<bool,void*>(true,m_priv->sendError(this, "session", mlp));
+    return pair<bool,void*>(true,m_priv->sendError(this, "session", mlp));
 }
 
 pair<bool,void*>
 ShibTarget::doCheckAuthZ(void)
 {
 #ifdef _DEBUG
-  saml::NDC ndc("ShibTarget::doCheckAuthZ");
+    saml::NDC ndc("ShibTarget::doCheckAuthZ");
 #endif
 
-  ShibMLP mlp;
-  const char *procState = "Authorization Processing Error";
-  const char *targetURL = NULL;
-  HTAccessInfo *ht = NULL;
-  HTGroupTable* grpstatus = NULL;
-
-  try {
-    if (! m_priv->m_app)
-      throw ShibTargetException(SHIBRPC_OK, "ShibTarget Uninitialized.  Application did not supply request information.");
-
-    targetURL = m_priv->m_url.c_str();
-    const char *session_id = m_priv->getSessionId(this);
-
-    // Do we have an access control plugin?
-    if (m_priv->m_settings.second) {
-      Locker acllock(m_priv->m_settings.second);
-      if (!m_priv->m_settings.second->authorized(*m_priv->m_sso_statement,
-            m_priv->m_post_response ? m_priv->m_post_response->getAssertions() : EMPTY(SAMLAssertion*))) {
-        log(LogLevelError, "doCheckAuthZ: access control provider denied access");
-        goto out;
-      }
-    }
+    ShibMLP mlp;
+    const char *procState = "Authorization Processing Error";
+    const char *targetURL = NULL;
+    HTAccessInfo *ht = NULL;
+    HTGroupTable* grpstatus = NULL;
 
-    // Perform HTAccess Checks
-    ht = getAccessInfo();
+    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 *session_id = m_priv->getSessionId(this);
+
+        // Do we have an access control plugin?
+        if (m_priv->m_settings.second) {
+            Locker acllock(m_priv->m_settings.second);
+            if (!m_priv->m_settings.second->authorized(*m_priv->m_sso_statement,
+                m_priv->m_post_response ? m_priv->m_post_response->getAssertions() : EMPTY(SAMLAssertion*))) {
+                log(LogLevelError, "doCheckAuthZ() access control provider denied access");
+                if (targetURL)
+                    mlp.insert("requestURL", targetURL);
+                // TODO: check setting and return 403
+                return pair<bool,void*>(true,m_priv->sendError(this, "access", mlp));
+            }
+        }
 
-    // No Info means OK.  Just return
-    if (!ht)
-      return pair<bool,void*>(false, NULL);
+        // Perform HTAccess Checks
+        ht = getAccessInfo();
 
-    vector<bool> auth_OK(ht->elements.size(), false);
-    bool method_restricted=false;
-    string remote_user = getRemoteUser();
+        // No Info means OK.  Just return
+        if (!ht)
+            return pair<bool,void*>(false, NULL);
+
+        vector<bool> auth_OK(ht->elements.size(), false);
+        bool method_restricted=false;
+        string remote_user = getRemoteUser();
 
     #define CHECK_OK do { \
       if (ht->requireAll) { \
@@ -484,383 +474,367 @@ ShibTarget::doCheckAuthZ(void)
       continue; \
     } while (0)
 
-    for (int x = 0; x < ht->elements.size(); x++) {
-      auth_OK[x] = false;
-      HTAccessInfo::RequireLine *line = ht->elements[x];
-      if (! line->use_line)
-        continue;
-      method_restricted = true;
-
-      const char *w = line->tokens[0].c_str();
-
-      if (!strcasecmp(w,"Shibboleth")) {
-        // This is a dummy rule needed because Apache conflates authn and authz.
-        // Without some require rule, AuthType is ignored and no check_user hooks run.
-        CHECK_OK;
-      }
-      else if (!strcmp(w,"valid-user")) {
-        log(LogLevelDebug, "doCheckAuthZ accepting valid-user");
-        CHECK_OK;
-      }
-      else if (!strcmp(w,"user") && !remote_user.empty()) {
-        bool regexp=false;
-        for (int i = 1; i < line->tokens.size(); i++) {
-          w = line->tokens[i].c_str();
-          if (*w == '~') {
-            regexp = true;
-            continue;
-          }
-                
-          if (regexp) {
-            try {
-              // To do regex matching, we have to convert from UTF-8.
-              auto_ptr<XMLCh> trans(fromUTF8(w));
-              RegularExpression re(trans.get());
-              auto_ptr<XMLCh> trans2(fromUTF8(remote_user.c_str()));
-              if (re.matches(trans2.get())) {
-                log(LogLevelDebug, string("doCheckAuthZ accepting user: ") + w);
-                CHECK_OK;
-              }
-            }
-            catch (XMLException& ex) {
-              auto_ptr_char tmp(ex.getMessage());
-              log(LogLevelError, string("doCheckAuthZ caught exception while parsing regular expression (")
-                 + w + "): " + tmp.get());
-            }
-          }
-          else if (!strcmp(remote_user.c_str(), w)) {
-            log(LogLevelDebug, string("doCheckAuthZ accepting user: ") + w);
-            CHECK_OK;
-          }
-        }
-      }
-      else if (!strcmp(w,"group")) {
-        grpstatus = getGroupTable(remote_user);
+        for (int x = 0; x < ht->elements.size(); x++) {
+            auth_OK[x] = false;
+            HTAccessInfo::RequireLine *line = ht->elements[x];
+            if (! line->use_line)
+                continue;
+            method_restricted = true;
 
-        if (!grpstatus) {
-          delete ht;
-          return pair<bool,void*>(true, returnDecline());
-        }
-    
-        for (int i = 1; i < line->tokens.size(); i++) {
-          w = line->tokens[i].c_str();
-          if (grpstatus->lookup(w)) {
-            log(LogLevelDebug, string("doCheckAuthZ accepting group: ") + w);
-            CHECK_OK;
-          }
-        }
-        delete grpstatus;
-        grpstatus = NULL;
-      }
-      else {
-        Iterator<IAAP*> provs = m_priv->m_app->getAAPProviders();
-        AAP wrapper(provs, w);
-        if (wrapper.fail()) {
-          log(LogLevelWarn, string("doCheckAuthZ didn't recognize require rule: ") + w);
-          continue;
-        }
+            const char *w = line->tokens[0].c_str();
 
-        bool regexp = false;
-        string vals = getHeader(wrapper->getHeader());
-        for (int i = 1; i < line->tokens.size() && !vals.empty(); i++) {
-          w = line->tokens[i].c_str();
-          if (*w == '~') {
-            regexp = true;
-            continue;
-          }
-
-          try {
-            auto_ptr<RegularExpression> re;
-            if (regexp) {
-              delete re.release();
-              auto_ptr<XMLCh> trans(fromUTF8(w));
-              auto_ptr<RegularExpression> temp(new RegularExpression(trans.get()));
-              re=temp;
+            if (!strcasecmp(w,"Shibboleth")) {
+                // This is a dummy rule needed because Apache conflates authn and authz.
+                // Without some require rule, AuthType is ignored and no check_user hooks run.
+                CHECK_OK;
             }
-                    
-            string vals_str(vals);
-            int j = 0;
-            for (int i = 0;  i < vals_str.length();  i++) {
-              if (vals_str.at(i) == ';') {
-                if (i == 0) {
-                  log(LogLevelError, string("doCheckAuthZ invalid header encoding") +
-                    vals + ": starts with a semicolon");
-                  goto out;
-                }
-
-                if (vals_str.at(i-1) == '\\') {
-                  vals_str.erase(i-1, 1);
-                  i--;
-                  continue;
-                }
-
-                string val = vals_str.substr(j, i-j);
-                j = i+1;
-                if (regexp) {
-                  auto_ptr<XMLCh> trans(fromUTF8(val.c_str()));
-                  if (re->matches(trans.get())) {
-                    log(LogLevelDebug, string("doCheckAuthZ expecting ") + w +
-                       ", got " + val + ": authorization granted");
-                    CHECK_OK;
-                  }
-                }
-                else if ((wrapper->getCaseSensitive() && val==w) ||
-                 (!wrapper->getCaseSensitive() && !strcasecmp(val.c_str(),w))) {
-                  log(LogLevelDebug, string("doCheckAuthZ expecting ") + w +
-                  ", got " + val + ": authorization granted.");
-                  CHECK_OK;
-                }
-                else {
-                    log(LogLevelDebug, string("doCheckAuthZ expecting ") + w +
-                        ", got " + val + ": authoritzation not granted.");
+            else if (!strcmp(w,"valid-user")) {
+                log(LogLevelDebug, "doCheckAuthZ accepting valid-user");
+                CHECK_OK;
+            }
+            else if (!strcmp(w,"user") && !remote_user.empty()) {
+                bool regexp=false;
+                for (int i = 1; i < line->tokens.size(); i++) {
+                    w = line->tokens[i].c_str();
+                    if (*w == '~') {
+                        regexp = true;
+                        continue;
+                    }
+                
+                    if (regexp) {
+                        try {
+                            // To do regex matching, we have to convert from UTF-8.
+                            auto_ptr<XMLCh> trans(fromUTF8(w));
+                            RegularExpression re(trans.get());
+                            auto_ptr<XMLCh> trans2(fromUTF8(remote_user.c_str()));
+                            if (re.matches(trans2.get())) {
+                                log(LogLevelDebug, string("doCheckAuthZ accepting user: ") + w);
+                                CHECK_OK;
+                            }
+                        }
+                        catch (XMLException& ex) {
+                            auto_ptr_char tmp(ex.getMessage());
+                            log(LogLevelError, string("doCheckAuthZ caught exception while parsing regular expression (")
+                              + w + "): " + tmp.get());
+                        }
+                    }
+                    else if (!strcmp(remote_user.c_str(), w)) {
+                        log(LogLevelDebug, string("doCheckAuthZ accepting user: ") + w);
+                        CHECK_OK;
+                    }
                 }
-              }
             }
+            else if (!strcmp(w,"group")) {
+                grpstatus = getGroupTable(remote_user);
+                if (!grpstatus) {
+                    delete ht;
+                    return pair<bool,void*>(true, returnDecline());
+                }
     
-            string val = vals_str.substr(j, vals_str.length()-j);
-            if (regexp) {
-              auto_ptr<XMLCh> trans(fromUTF8(val.c_str()));
-              if (re->matches(trans.get())) {
-                log(LogLevelDebug, string("doCheckAuthZ expecting ") + w +
-                    ", got " + val + ": authorization granted.");
-                CHECK_OK;
-              }
-            }
-            else if ((wrapper->getCaseSensitive() && val==w) ||
-                    (!wrapper->getCaseSensitive() && !strcasecmp(val.c_str(),w))) {
-              log(LogLevelDebug, string("doCheckAuthZ expecting ") + w +
-              ", got " + val + ": authorization granted");
-              CHECK_OK;
+                for (int i = 1; i < line->tokens.size(); i++) {
+                    w = line->tokens[i].c_str();
+                    if (grpstatus->lookup(w)) {
+                        log(LogLevelDebug, string("doCheckAuthZ accepting group: ") + w);
+                        CHECK_OK;
+                    }
+                }
+                delete grpstatus;
+                grpstatus = NULL;
             }
             else {
-              log(LogLevelDebug, string("doCheckAuthZ expecting ") + w +
-              ", got " + val + ": authorization not granted");
-            }
-          }
-          catch (XMLException& ex) {
-            auto_ptr_char tmp(ex.getMessage());
-            log(LogLevelError, string("doCheckAuthZ caught exception while parsing regular expression (")
-                + w + "): " + tmp.get());
-          }
-        }
-      }
-    } // for x
+                Iterator<IAAP*> provs = m_priv->m_app->getAAPProviders();
+                AAP wrapper(provs, w);
+                if (wrapper.fail()) {
+                    log(LogLevelWarn, string("doCheckAuthZ didn't recognize require rule: ") + w);
+                    continue;
+                }
 
+                bool regexp = false;
+                string vals = getHeader(wrapper->getHeader());
+                for (int i = 1; i < line->tokens.size() && !vals.empty(); i++) {
+                    w = line->tokens[i].c_str();
+                    if (*w == '~') {
+                        regexp = true;
+                        continue;
+                    }
+
+                    try {
+                        auto_ptr<RegularExpression> re;
+                        if (regexp) {
+                            delete re.release();
+                            auto_ptr<XMLCh> trans(fromUTF8(w));
+                            auto_ptr<RegularExpression> temp(new RegularExpression(trans.get()));
+                            re=temp;
+                        }
+                    
+                        string vals_str(vals);
+                        int j = 0;
+                        for (int i = 0;  i < vals_str.length();  i++) {
+                            if (vals_str.at(i) == ';') {
+                                if (i == 0) {
+                                    log(LogLevelError, string("doCheckAuthZ invalid header encoding") +
+                                        vals + ": starts with a semicolon");
+                                    throw SAMLException("Invalid information supplied to authorization module.");
+                                }
+
+                                if (vals_str.at(i-1) == '\\') {
+                                    vals_str.erase(i-1, 1);
+                                    i--;
+                                    continue;
+                                }
+
+                                string val = vals_str.substr(j, i-j);
+                                j = i+1;
+                                if (regexp) {
+                                    auto_ptr<XMLCh> trans(fromUTF8(val.c_str()));
+                                    if (re->matches(trans.get())) {
+                                        log(LogLevelDebug, string("doCheckAuthZ expecting ") + w +
+                                          ", got " + val + ": authorization granted");
+                                        CHECK_OK;
+                                    }
+                                }
+                                else if ((wrapper->getCaseSensitive() && val==w) ||
+                                        (!wrapper->getCaseSensitive() && !strcasecmp(val.c_str(),w))) {
+                                    log(LogLevelDebug, string("doCheckAuthZ expecting ") + w +
+                                        ", got " + val + ": authorization granted.");
+                                    CHECK_OK;
+                                }
+                                else {
+                                    log(LogLevelDebug, string("doCheckAuthZ expecting ") + w +
+                                        ", got " + val + ": authoritzation not granted.");
+                                }
+                            }
+                        }
+    
+                        string val = vals_str.substr(j, vals_str.length()-j);
+                        if (regexp) {
+                            auto_ptr<XMLCh> trans(fromUTF8(val.c_str()));
+                            if (re->matches(trans.get())) {
+                                log(LogLevelDebug, string("doCheckAuthZ expecting ") + w +
+                                    ", got " + val + ": authorization granted.");
+                                CHECK_OK;
+                            }
+                        }
+                        else if ((wrapper->getCaseSensitive() && val==w) ||
+                                (!wrapper->getCaseSensitive() && !strcasecmp(val.c_str(),w))) {
+                            log(LogLevelDebug, string("doCheckAuthZ expecting ") + w +
+                                ", got " + val + ": authorization granted");
+                            CHECK_OK;
+                        }
+                        else {
+                            log(LogLevelDebug, string("doCheckAuthZ expecting ") + w +
+                                ", got " + val + ": authorization not granted");
+                        }
+                    }
+                    catch (XMLException& ex) {
+                        auto_ptr_char tmp(ex.getMessage());
+                            log(LogLevelError, string("doCheckAuthZ caught exception while parsing regular expression (")
+                                + w + "): " + tmp.get());
+                    }
+                }
+            }
+        } // for x
 
-    // check if all require directives are true
-    bool auth_all_OK = true;
-    for (int i = 0; i < ht->elements.size(); i++) {
-        auth_all_OK &= auth_OK[i];
-    }
 
-    delete ht;
-    if (grpstatus) delete grpstatus;
-    if (auth_all_OK || !method_restricted)
-      return pair<bool,void*>(false, NULL);
+        // check if all require directives are true
+        bool auth_all_OK = true;
+        for (int i = 0; i < ht->elements.size(); i++) {
+            auth_all_OK &= auth_OK[i];
+        }
 
-    // If we get here there's an access error, so just fall through
+        delete ht;
+        if (grpstatus) delete grpstatus;
+        if (auth_all_OK || !method_restricted)
+            return pair<bool,void*>(false, NULL);
 
-  }
-  catch (ShibTargetException &e) {
-    mlp.insert("errorText", e.what());
-  }
+        // If we get here there's an access error, so just fall through
+    }
+    catch (SAMLException& e) {
+        mlp.insert(e);
+    }
 #ifndef _DEBUG
-  catch (...) {
-    mlp.insert("errorText", "Unexpected Exception");
-  }
+    catch (...) {
+        mlp.insert("errorText", "Caught an unknown exception.");
+    }
 #endif
 
-  // If we get here then we've got an error.
-  mlp.insert("errorType", procState);
-  mlp.insert("errorDesc", "An error occurred while processing your request.");
+    // If we get here then we've got an error.
+    mlp.insert("errorType", procState);
 
- out:
-  if (targetURL)
-    mlp.insert("requestURL", targetURL);
+    if (targetURL)
+        mlp.insert("requestURL", targetURL);
 
-  if (ht)
     delete ht;
 
-  return pair<bool,void*>(true,m_priv->sendError(this, "access", mlp));
+    return pair<bool,void*>(true,m_priv->sendError(this, "access", mlp));
 }
 
 pair<bool,void*>
 ShibTarget::doExportAssertions(bool exportAssertion)
 {
 #ifdef _DEBUG
-  saml::NDC ndc("ShibTarget::doExportAssertions");
+    saml::NDC ndc("ShibTarget::doExportAssertions");
 #endif
 
-  ShibMLP mlp;
-  const char *procState = "Attribute Processing Error";
-  const char *targetURL = NULL;
-  char *page = "rm";
-
-  try {
-    if (! m_priv->m_app)
-      throw ShibTargetException(SHIBRPC_OK, "ShibTarget Uninitialized.  Application did not supply request information.");
-
-    targetURL = m_priv->m_url.c_str();
-    const char *session_id = m_priv->getSessionId(this);
-
-    if (!m_priv->m_sso_statement) {
-        // No data yet, so we need to get the session. This can only happen
-        // if the call to doCheckAuthn doesn't happen in the same object lifetime.
-        RPCError* status = sessionGet(
-            session_id,
-            m_priv->m_remote_addr.c_str(),
-            m_priv->m_sso_profile,
-            m_priv->m_provider_id,
-            &m_priv->m_sso_statement,
-            &m_priv->m_pre_response,
-            &m_priv->m_post_response
-            );
-        if (status->isError()) {
-            string er = "sessionGet failed: ";
-            er += status->getText();
-            log(ShibTarget::LogLevelError, er);
-            mlp.insert(*status);
-            delete status;
-            goto out;
+    ShibMLP mlp;
+    const char *procState = "Attribute Processing Error";
+    const char *targetURL = NULL;
+    char *page = "rm";
+
+    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 *session_id = m_priv->getSessionId(this);
+
+        if (!m_priv->m_sso_statement) {
+            // No data yet, so we need to get the session. This can only happen
+            // if the call to doCheckAuthn doesn't happen in the same object lifetime.
+            sessionGet(
+                session_id,
+                m_priv->m_remote_addr.c_str(),
+                m_priv->m_sso_profile,
+                m_priv->m_provider_id,
+                &m_priv->m_sso_statement,
+                &m_priv->m_pre_response,
+                &m_priv->m_post_response
+                );
         }
-        delete status;
-    }
 
-    // Get the AAP providers, which contain the attribute policy info.
-    Iterator<IAAP*> provs=m_priv->m_app->getAAPProviders();
-
-    // Clear out the list of mapped attributes
-    while (provs.hasNext()) {
-      IAAP* aap=provs.next();
-      Locker locker(aap);
-      Iterator<const IAttributeRule*> rules=aap->getAttributeRules();
-      while (rules.hasNext()) {
-          const char* header=rules.next()->getHeader();
-          if (header)
-            clearHeader(header);
-      }
-    }
-    
-    // Maybe export the first assertion.
-    clearHeader("Shib-Attributes");
-    pair<bool,bool> exp=m_priv->m_settings.first->getBool("exportAssertion");
-    if (!exp.first || !exp.second)
-      if (exportAssertion)
-        exp.second=true;
-    if (exp.second && m_priv->m_pre_response) {
-      ostringstream os;
-      os << *(m_priv->m_pre_response);
-      unsigned int outlen;
-      char* resp = (char*)os.str().c_str();
-      XMLByte* serialized = Base64::encode(reinterpret_cast<XMLByte*>(resp), os.str().length(), &outlen);
-      setHeader("Shib-Attributes", reinterpret_cast<char*>(serialized));
-      XMLString::release(&serialized);
-    }
+        // Get the AAP providers, which contain the attribute policy info.
+        Iterator<IAAP*> provs=m_priv->m_app->getAAPProviders();
 
-    // Export the SAML AuthnMethod and the origin site name, and possibly the NameIdentifier.
-    clearHeader("Shib-Origin-Site");
-    clearHeader("Shib-Identity-Provider");
-    clearHeader("Shib-Authentication-Method");
-    clearHeader("Shib-NameIdentifier-Format");
-    setHeader("Shib-Origin-Site", m_priv->m_provider_id.c_str());
-    setHeader("Shib-Identity-Provider", m_priv->m_provider_id.c_str());
-    auto_ptr_char am(m_priv->m_sso_statement->getAuthMethod());
-    setHeader("Shib-Authentication-Method", am.get());
-    
-    // Export NameID?
-    provs.reset();
-    while (provs.hasNext()) {
-        IAAP* aap=provs.next();
-        Locker locker(aap);
-        const IAttributeRule* rule=aap->lookup(m_priv->m_sso_statement->getSubject()->getNameIdentifier()->getFormat());
-        if (rule && rule->getHeader()) {
-          auto_ptr_char form(m_priv->m_sso_statement->getSubject()->getNameIdentifier()->getFormat());
-          auto_ptr_char nameid(m_priv->m_sso_statement->getSubject()->getNameIdentifier()->getName());
-          setHeader("Shib-NameIdentifier-Format", form.get());
-          if (!strcmp(rule->getHeader(),"REMOTE_USER"))
-            setRemoteUser(nameid.get());
-          else
-            setHeader(rule->getHeader(), nameid.get());
+        // Clear out the list of mapped attributes
+        while (provs.hasNext()) {
+            IAAP* aap=provs.next();
+            Locker locker(aap);
+            Iterator<const IAttributeRule*> rules=aap->getAttributeRules();
+            while (rules.hasNext()) {
+                const char* header=rules.next()->getHeader();
+                if (header)
+                    clearHeader(header);
+            }
+        }
+        
+        // Maybe export the first assertion.
+        clearHeader("Shib-Attributes");
+        pair<bool,bool> exp=m_priv->m_settings.first->getBool("exportAssertion");
+        if (!exp.first || !exp.second)
+            if (exportAssertion)
+                exp.second=true;
+        if (exp.second && m_priv->m_pre_response) {
+            ostringstream os;
+            os << *(m_priv->m_pre_response);
+            unsigned int outlen;
+            char* resp = (char*)os.str().c_str();
+            XMLByte* serialized = Base64::encode(reinterpret_cast<XMLByte*>(resp), os.str().length(), &outlen);
+            // TODO: strip linefeeds
+            setHeader("Shib-Attributes", reinterpret_cast<char*>(serialized));
+            XMLString::release(&serialized);
         }
-    }
     
-    clearHeader("Shib-Application-ID");
-    setHeader("Shib-Application-ID", m_priv->m_app->getId());
-
-    // Export the attributes.
-    Iterator<SAMLAssertion*> a_iter(m_priv->m_post_response ? m_priv->m_post_response->getAssertions() : EMPTY(SAMLAssertion*));
-    while (a_iter.hasNext()) {
-      SAMLAssertion* assert=a_iter.next();
-      Iterator<SAMLStatement*> statements=assert->getStatements();
-      while (statements.hasNext()) {
-        SAMLAttributeStatement* astate=dynamic_cast<SAMLAttributeStatement*>(statements.next());
-        if (!astate)
-            continue;
-        Iterator<SAMLAttribute*> attrs=astate->getAttributes();
-        while (attrs.hasNext()) {
-          SAMLAttribute* attr=attrs.next();
+        // Export the SAML AuthnMethod and the origin site name, and possibly the NameIdentifier.
+        clearHeader("Shib-Origin-Site");
+        clearHeader("Shib-Identity-Provider");
+        clearHeader("Shib-Authentication-Method");
+        clearHeader("Shib-NameIdentifier-Format");
+        setHeader("Shib-Origin-Site", m_priv->m_provider_id.c_str());
+        setHeader("Shib-Identity-Provider", m_priv->m_provider_id.c_str());
+        auto_ptr_char am(m_priv->m_sso_statement->getAuthMethod());
+        setHeader("Shib-Authentication-Method", am.get());
         
-          // Are we supposed to export it?
-          provs.reset();
-          while (provs.hasNext()) {
+        // Export NameID?
+        provs.reset();
+        while (provs.hasNext()) {
             IAAP* aap=provs.next();
             Locker locker(aap);
-            const IAttributeRule* rule=aap->lookup(attr->getName(),attr->getNamespace());
-            if (!rule || !rule->getHeader()) {
-                continue;
+            const IAttributeRule* rule=aap->lookup(m_priv->m_sso_statement->getSubject()->getNameIdentifier()->getFormat());
+            if (rule && rule->getHeader()) {
+                auto_ptr_char form(m_priv->m_sso_statement->getSubject()->getNameIdentifier()->getFormat());
+                auto_ptr_char nameid(m_priv->m_sso_statement->getSubject()->getNameIdentifier()->getName());
+                setHeader("Shib-NameIdentifier-Format", form.get());
+                if (!strcmp(rule->getHeader(),"REMOTE_USER"))
+                    setRemoteUser(nameid.get());
+                else
+                    setHeader(rule->getHeader(), nameid.get());
             }
-                
-            Iterator<string> vals=attr->getSingleByteValues();
-            if (!strcmp(rule->getHeader(),"REMOTE_USER") && vals.hasNext())
-                setRemoteUser(vals.next());
-            else {
-                int it=0;
-                string header = getHeader(rule->getHeader());
-                if (!header.empty())
-                  it++;
-                for (; vals.hasNext(); it++) {
-                  string value = vals.next();
-                  for (string::size_type pos = value.find_first_of(";", string::size_type(0));
-                  pos != string::npos;
-                  pos = value.find_first_of(";", pos)) {
-               value.insert(pos, "\\");
-               pos += 2;
-                  }
-                  if (it)
-               header += ";";
-                  header += value;
+        }
+        
+        clearHeader("Shib-Application-ID");
+        setHeader("Shib-Application-ID", m_priv->m_app->getId());
+    
+        // Export the attributes.
+        Iterator<SAMLAssertion*> a_iter(m_priv->m_post_response ? m_priv->m_post_response->getAssertions() : EMPTY(SAMLAssertion*));
+        while (a_iter.hasNext()) {
+            SAMLAssertion* assert=a_iter.next();
+            Iterator<SAMLStatement*> statements=assert->getStatements();
+            while (statements.hasNext()) {
+                SAMLAttributeStatement* astate=dynamic_cast<SAMLAttributeStatement*>(statements.next());
+                if (!astate)
+                    continue;
+                Iterator<SAMLAttribute*> attrs=astate->getAttributes();
+                while (attrs.hasNext()) {
+                    SAMLAttribute* attr=attrs.next();
+            
+                    // Are we supposed to export it?
+                    provs.reset();
+                    while (provs.hasNext()) {
+                        IAAP* aap=provs.next();
+                        Locker locker(aap);
+                        const IAttributeRule* rule=aap->lookup(attr->getName(),attr->getNamespace());
+                        if (!rule || !rule->getHeader())
+                            continue;
+                    
+                        Iterator<string> vals=attr->getSingleByteValues();
+                        if (!strcmp(rule->getHeader(),"REMOTE_USER") && vals.hasNext())
+                            setRemoteUser(vals.next());
+                        else {
+                            int it=0;
+                            string header = getHeader(rule->getHeader());
+                            if (!header.empty())
+                                it++;
+                            for (; vals.hasNext(); it++) {
+                                string value = vals.next();
+                                for (string::size_type pos = value.find_first_of(";", string::size_type(0));
+                                        pos != string::npos;
+                                        pos = value.find_first_of(";", pos)) {
+                                    value.insert(pos, "\\");
+                                    pos += 2;
+                                }
+                                if (it)
+                                    header += ";";
+                                header += value;
+                            }
+                            setHeader(rule->getHeader(), header);
+                        }
+                    }
                 }
-                setHeader(rule->getHeader(), header);
             }
-          }
         }
-      }
+    
+        return pair<bool,void*>(false,NULL);
+    }
+    catch (SAMLException& e) {
+        mlp.insert(e);
     }
-
-    return pair<bool,void*>(false,NULL);
-  }
-  catch (ShibTargetException &e) {
-    mlp.insert("errorText", e.what());
-  }
 #ifndef _DEBUG
-  catch (...) {
-    mlp.insert("errorText", "Unexpected Exception");
-  }
+    catch (...) {
+        mlp.insert("errorText", "Caught an unknown exception.");
+    }
 #endif
 
-  // If we get here then we've got an error.
-  mlp.insert("errorType", procState);
-  mlp.insert("errorDesc", "An error occurred while processing your request.");
+    // If we get here then we've got an error.
+    mlp.insert("errorType", procState);
 
- out:
-  if (targetURL)
-    mlp.insert("requestURL", targetURL);
+    if (targetURL)
+        mlp.insert("requestURL", targetURL);
 
-  return pair<bool,void*>(true,m_priv->sendError(this, page, mlp));
+    return pair<bool,void*>(true,m_priv->sendError(this, page, mlp));
 }
 
 
-// SHIRE APIs
+// Low level APIs
 
 // Get the session cookie name and properties for the application
 pair<string,const char*> ShibTarget::getCookieNameProps(const char* prefix) const
@@ -987,7 +961,7 @@ string ShibTarget::getAuthnRequest(const char* resource)
                 // 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,m_priv->url_encode(resource) + shib_cookie.second);
-                req += "&target=42";
+                req += "&target=cookie";
             }
             
             pair<bool,bool> old=m_priv->m_app->getBool("oldAuthnRequest");
@@ -1011,7 +985,7 @@ string ShibTarget::getLazyAuthnRequest(const char* query_string)
     return getAuthnRequest(target);
 }
 
-RPCError* ShibTarget::sessionNew(
+void ShibTarget::sessionNew(
     int supported_profiles,
     const char* packet,
     const char* ip,
@@ -1020,79 +994,104 @@ RPCError* ShibTarget::sessionNew(
     ) const
 {
 #ifdef _DEBUG
-  saml::NDC ndc("sessionNew");
+    saml::NDC ndc("sessionNew");
 #endif
-  Category& log = Category::getInstance("shibtarget.ShibTarget");
+    Category& log = Category::getInstance("shibtarget.ShibTarget");
 
-  if (!packet || !*packet) {
-    log.error("Empty profile content");
-    return new RPCError(SHIBRPC_RESPONSE_MISSING, "Empty profile content");
-  }
+    if (!packet || !*packet) {
+        log.error("missing profile response");
+        throw FatalProfileException("Profile response missing.");
+    }
 
-  if (!ip || !*ip) {
-    log.error("Invalid IP address");
-    return new RPCError(SHIBRPC_IPADDR_MISSING, "Invalid IP address");
-  }
+    if (!ip || !*ip) {
+        log.error("missing client address");
+        throw FatalProfileException("Invalid client address.");
+    }
   
-  if (supported_profiles <= 0) {
-    log.error("No profile support indicated");
-    return new RPCError(SHIBRPC_INTERNAL_ERROR, "No profile support indicated");
-  }
+    if (supported_profiles <= 0) {
+        log.error("no profile support indicated");
+        throw FatalProfileException("No profile support indicated.");
+    }
   
-  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.packet = (char*)packet;
-  arg.client_addr = (char*)ip;
-  arg.supported_profiles = supported_profiles;
-
-  log.info("create session for user at (%s) for application (%s)", ip, arg.application_id);
-
-  shibrpc_new_session_ret_2 ret;
-  memset(&ret, 0, sizeof(ret));
-
-  // Loop on the RPC in case we lost contact the first time through
-  int retry = 1;
-  CLIENT* clnt;
-  RPC rpc;
-  do {
-    clnt = rpc->connect();
-    clnt_stat status = shibrpc_new_session_2 (&arg, &ret, clnt);
-    if (status != RPC_SUCCESS) {
-      // FAILED.  Release, disconnect, and retry
-      log.error("RPC Failure: %p (%p) (%d): %s", this, clnt, status, clnt_spcreateerror("shibrpc_new_session_2"));
-      rpc->disconnect();
-      if (retry)
-        retry--;
-      else
-        return new RPCError(-1, "RPC Failure");
+    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.packet = (char*)packet;
+    arg.client_addr = (char*)ip;
+    arg.supported_profiles = supported_profiles;
+
+    log.info("create session for user at (%s) for application (%s)", ip, arg.application_id);
+
+    shibrpc_new_session_ret_2 ret;
+    memset(&ret, 0, sizeof(ret));
+
+    // Loop on the RPC in case we lost contact the first time through
+    int retry = 1;
+    CLIENT* clnt;
+    RPC rpc;
+    do {
+        clnt = rpc->connect();
+        clnt_stat status = shibrpc_new_session_2 (&arg, &ret, clnt);
+        if (status != RPC_SUCCESS) {
+            // FAILED.  Release, disconnect, and retry
+            log.error("RPC Failure: %p (%p) (%d): %s", this, clnt, status, clnt_spcreateerror("shibrpc_new_session_2"));
+            rpc->disconnect();
+            if (retry)
+                retry--;
+            else
+                throw ListenerException("Failure passing session setup information to listener.");
+        }
+        else {
+            // SUCCESS.  Pool and continue
+            retry = -1;
+        }
+    } while (retry>=0);
+
+    if (ret.status && *ret.status)
+        log.debug("RPC completed with exception: %s", ret.status);
+    else
+        log.debug("RPC completed successfully");
+
+    SAMLException* except=NULL;
+    if (ret.status && *ret.status) {
+        // Reconstitute exception object.
+        try { 
+            istringstream estr(ret.status);
+            except=SAMLException::getInstance(estr);
+        }
+        catch (SAMLException& e) {
+            log.error("caught SAML Exception while building the SAMLException: %s", e.what());
+            log.error("XML was: %s", ret.status);
+            clnt_freeres(clnt, (xdrproc_t)xdr_shibrpc_new_session_ret_2, (caddr_t)&ret);
+            rpc.pool();
+            throw FatalProfileException("An unrecoverable error occurred while creating your session.");
+        }
+#ifndef _DEBUG
+        catch (...) {
+            log.error("caught unknown exception building SAMLException");
+            log.error("XML was: %s", ret.status);
+            clnt_freeres(clnt, (xdrproc_t)xdr_shibrpc_new_session_ret_2, (caddr_t)&ret);
+            rpc.pool();
+            throw;
+        }
+#endif
     }
     else {
-      // SUCCESS.  Pool and continue
-      retry = -1;
+        log.debug("new session cookie: %s", ret.cookie);
+        cookie = ret.cookie;
+        if (ret.target)
+            target = ret.target;
     }
-  } while (retry>=0);
-
-  log.debug("RPC completed with status %d (%p)", ret.status.status, this);
-
-  RPCError* retval;
-  if (ret.status.status)
-    retval = new RPCError(&ret.status);
-  else {
-    log.debug ("new session cookie: %s", ret.cookie);
-    cookie = ret.cookie;
-    if (ret.target)
-        target = ret.target;
-    retval = new RPCError();
-  }
-
-  clnt_freeres(clnt, (xdrproc_t)xdr_shibrpc_new_session_ret_2, (caddr_t)&ret);
-  rpc.pool();
 
-  return retval;
+    clnt_freeres(clnt, (xdrproc_t)xdr_shibrpc_new_session_ret_2, (caddr_t)&ret);
+    rpc.pool();
+    if (except) {
+        auto_ptr<SAMLException> wrapper(except);
+        throw *wrapper;
+    }
 }
 
-RPCError* ShibTarget::sessionGet(
+void ShibTarget::sessionGet(
     const char* cookie,
     const char* ip,
     ShibProfile& profile,
@@ -1103,120 +1102,135 @@ RPCError* ShibTarget::sessionGet(
     ) const
 {
 #ifdef _DEBUG
-  saml::NDC ndc("sessionGet");
+    saml::NDC ndc("sessionGet");
 #endif
-  Category& log = Category::getInstance("shibtarget.ShibTarget");
-
-  if (!cookie || !*cookie) {
-    log.error("No cookie value was provided");
-    return new RPCError(SHIBRPC_NO_SESSION, "No cookie value was provided");
-  }
-  else if (strchr(cookie,'=')) {
-    log.error("The cookie value wasn't extracted successfully, use a more unique cookie name for your installation.");
-    return new RPCError(SHIBRPC_INTERNAL_ERROR, "The cookie value wasn't extracted successfully, use a more unique cookie name for your installation.");
-  }
-
-  if (!ip || !*ip) {
-    log.error("Invalid IP Address");
-    return new RPCError(SHIBRPC_IPADDR_MISSING, "Invalid IP Address");
-  }
+    Category& log = Category::getInstance("shibtarget.ShibTarget");
 
-  log.info("getting session for client at (%s)", ip);
-  log.debug("session cookie (%s)", cookie);
-
-  shibrpc_get_session_args_2 arg;
-
-  arg.cookie = (char*)cookie;
-  arg.client_addr = (char*)ip;
-  arg.application_id = (char*)m_priv->m_app->getId();
-
-  shibrpc_get_session_ret_2 ret;
-  memset (&ret, 0, sizeof(ret));
-
-  // Loop on the RPC in case we lost contact the first time through
-  int retry = 1;
-  CLIENT *clnt;
-  RPC rpc;
-  do {
-    clnt = rpc->connect();
-    clnt_stat status = shibrpc_get_session_2(&arg, &ret, clnt);
-    if (status != RPC_SUCCESS) {
-      // FAILED.  Release, disconnect, and try again...
-      log.error("RPC Failure: %p (%p) (%d) %s", this, clnt, status, clnt_spcreateerror("shibrpc_get_session_2"));
-      rpc->disconnect();
-      if (retry)
-          retry--;
-      else
-          return new RPCError(-1, "RPC Failure");
+    if (!cookie || !*cookie) {
+        log.error("no session key provided");
+        throw InvalidSessionException("No session key was provided.");
     }
-    else {
-      // SUCCESS
-      retry = -1;
+    else if (strchr(cookie,'=')) {
+        log.error("cookie value not extracted successfully, probably overlapping cookies across domains");
+        throw InvalidSessionException("The session key wasn't extracted successfully from the browser cookie.");
     }
-  } while (retry>=0);
 
-  log.debug("RPC completed with status %d, %p", ret.status.status, this);
+    if (!ip || !*ip) {
+        log.error("invalid client Address");
+        throw FatalProfileException("Invalid client address.");
+    }
 
-  RPCError* retval = NULL;
-  if (ret.status.status)
-    retval = new RPCError(&ret.status);
-  else {
-    try {
-      try {
-        profile = ret.profile;
-        provider_id = ret.provider_id;
-        
-        // return the Authentication Statement
-        if (auth_statement) {
-          istringstream authstream(ret.auth_statement);
-          
-          log.debugStream() << "Trying to decode authentication statement: "
-                << ret.auth_statement << CategoryStream::ENDLINE;
-          *auth_statement = new SAMLAuthenticationStatement(authstream);
+    log.info("getting session for client at (%s)", ip);
+    log.debug("session cookie (%s)", cookie);
+
+    shibrpc_get_session_args_2 arg;
+    arg.cookie = (char*)cookie;
+    arg.client_addr = (char*)ip;
+    arg.application_id = (char*)m_priv->m_app->getId();
+
+    shibrpc_get_session_ret_2 ret;
+    memset (&ret, 0, sizeof(ret));
+
+    // Loop on the RPC in case we lost contact the first time through
+    int retry = 1;
+    CLIENT *clnt;
+    RPC rpc;
+    do {
+        clnt = rpc->connect();
+        clnt_stat status = shibrpc_get_session_2(&arg, &ret, clnt);
+        if (status != RPC_SUCCESS) {
+            // FAILED.  Release, disconnect, and try again...
+            log.error("RPC Failure: %p (%p) (%d) %s", this, clnt, status, clnt_spcreateerror("shibrpc_get_session_2"));
+            rpc->disconnect();
+            if (retry)
+                retry--;
+            else
+                throw ListenerException("Failure requesting session information from listener.");
         }
-
-        // return the unfiltered Response
-        if (attr_response_pre) {
-          istringstream prestream(ret.attr_response_pre);
-          
-          log.debugStream() << "Trying to decode unfiltered attribute response: "
-                << ret.attr_response_pre << CategoryStream::ENDLINE;
-          *attr_response_pre = new SAMLResponse(prestream);
+        else {
+            // SUCCESS
+            retry = -1;
         }
+    } while (retry>=0);
 
-        // return the filtered Response
-        if (attr_response_post) {
-          istringstream poststream(ret.attr_response_post);
-          
-          log.debugStream() << "Trying to decode filtered attribute response: "
-                << ret.attr_response_post << CategoryStream::ENDLINE;
-          *attr_response_post = new SAMLResponse(poststream);
+    if (ret.status && *ret.status)
+        log.debug("RPC completed with exception: %s", ret.status);
+    else
+        log.debug("RPC completed successfully");
+
+    SAMLException* except=NULL;
+    if (ret.status && *ret.status) {
+        // Reconstitute exception object.
+        try { 
+            istringstream estr(ret.status);
+            except=SAMLException::getInstance(estr);
+        }
+        catch (SAMLException& e) {
+            log.error("caught SAML Exception while building the SAMLException: %s", e.what());
+            log.error("XML was: %s", ret.status);
+            clnt_freeres(clnt, (xdrproc_t)xdr_shibrpc_get_session_ret_2, (caddr_t)&ret);
+            rpc.pool();
+            throw FatalProfileException("An unrecoverable error occurred while accessing your session.");
+        }
+        catch (...) {
+            log.error("caught unknown exception building SAMLException");
+            log.error("XML was: %s", ret.status);
+            clnt_freeres(clnt, (xdrproc_t)xdr_shibrpc_get_session_ret_2, (caddr_t)&ret);
+            rpc.pool();
+            throw;
         }
-      }
-      catch (SAMLException& e) {
-        log.error ("SAML Exception: %s", e.what());
-        ostringstream os;
-        os << e;
-        throw ShibTargetException(SHIBRPC_SAML_EXCEPTION, os.str().c_str());
-      }
-      catch (XMLException& e) {
-        log.error ("XML Exception: %s", e.getMessage());
-        auto_ptr_char msg(e.getMessage());
-        throw ShibTargetException (SHIBRPC_XML_EXCEPTION, msg.get());
-      }
     }
-    catch (ShibTargetException &e) {
-      retval = new RPCError(e);
+    else {
+        try {
+            profile = ret.profile;
+            provider_id = ret.provider_id;
+        
+            // return the Authentication Statement
+            if (auth_statement) {
+                istringstream authstream(ret.auth_statement);
+                log.debugStream() << "trying to decode authentication statement: "
+                    << ret.auth_statement << CategoryStream::ENDLINE;
+                *auth_statement = new SAMLAuthenticationStatement(authstream);
+            }
+    
+            // return the unfiltered Response
+            if (attr_response_pre) {
+                istringstream prestream(ret.attr_response_pre);
+                log.debugStream() << "trying to decode unfiltered attribute response: "
+                    << ret.attr_response_pre << CategoryStream::ENDLINE;
+                *attr_response_pre = new SAMLResponse(prestream);
+            }
+    
+            // return the filtered Response
+            if (attr_response_post) {
+                istringstream poststream(ret.attr_response_post);
+                log.debugStream() << "trying to decode filtered attribute response: "
+                    << ret.attr_response_post << CategoryStream::ENDLINE;
+                *attr_response_post = new SAMLResponse(poststream);
+            }
+        }
+        catch (SAMLException& e) {
+            log.error("caught SAML exception while reconstituting session objects: %s", e.what());
+            clnt_freeres (clnt, (xdrproc_t)xdr_shibrpc_get_session_ret_2, (caddr_t)&ret);
+            rpc.pool();
+            throw;
+        }
+#ifndef _DEBUG
+        catch (...) {
+            log.error("caught unknown exception while reconstituting session objects");
+            clnt_freeres (clnt, (xdrproc_t)xdr_shibrpc_get_session_ret_2, (caddr_t)&ret);
+            rpc.pool();
+            throw;
+        }
+#endif
     }
 
-    if (!retval)
-      retval = new RPCError();
-  }
-
-  clnt_freeres (clnt, (xdrproc_t)xdr_shibrpc_get_session_ret_2, (caddr_t)&ret);
-  rpc.pool();
-
-  return retval;
+    clnt_freeres (clnt, (xdrproc_t)xdr_shibrpc_get_session_ret_2, (caddr_t)&ret);
+    rpc.pool();
+    if (except) {
+        auto_ptr<SAMLException> wrapper(except);
+        throw *wrapper;
+    }
 }
 
 /*************************************************************************
@@ -1302,7 +1316,7 @@ ShibTargetPriv::get_application(const string& protocol, const string& hostname,
     m_mapper = NULL;
     m_conf->unlock();
     m_conf = NULL;
-    throw ShibTargetException(SHIBRPC_OK, "unable to map request to application settings.  Check configuration");
+    throw SAMLException("Unable to map request to application settings, check configuration.");
   }
 
   // Store the application for later use
@@ -1319,23 +1333,24 @@ ShibTargetPriv::get_application(const string& protocol, const string& hostname,
 void*
 ShibTargetPriv::sendError(ShibTarget* st, string page, ShibMLP &mlp)
 {
-  const IPropertySet* props=m_app->getPropertySet("Errors");
-  if (props) {
-    pair<bool,const char*> p=props->getString(page.c_str());
-    if (p.first) {
-      ifstream infile(p.second);
-      if (!infile.fail()) {
-       const char* res = mlp.run(infile,props);
-       if (res)
-         return st->sendPage(res);
-      }
+    const IPropertySet* props=m_app->getPropertySet("Errors");
+    if (props) {
+        pair<bool,const char*> p=props->getString(page.c_str());
+        if (p.first) {
+            ifstream infile(p.second);
+            if (!infile.fail()) {
+                const char* res = mlp.run(infile,props);
+                if (res)
+                    return st->sendPage(res);
+            }
+        }
     }
-  }
 
-  string errstr = "sendError could not process the error template for application ";
-  errstr += m_app->getId();
-  st->log(ShibTarget::LogLevelError, errstr);
-  return st->sendPage("Internal Server Error.  Please contact the server administrator.");
+    string errstr = "sendError could not process the error template for application (";
+    errstr += m_app->getId();
+    errstr += ")";
+    st->log(ShibTarget::LogLevelError, errstr);
+    return st->sendPage("Internal Server Error. Please contact the site administrator.");
 }
 
 const char* ShibTargetPriv::getSessionId(ShibTarget* st)
index 7857599..90a1b15 100644 (file)
 
 namespace shibtarget {
   
-  //******************************************************************************
-  // You probably don't care about much below this line
-  // unless you are using the lower-layer APIs provided by
-  // the shib target library.  Go to the end of the file to
-  // find the ShibTarget class -- you probably wnat to use that.
-  //
-
-  class SHIBTARGET_EXPORTS ShibTargetException : public std::exception
-  {
-  public:
-    explicit ShibTargetException() : m_code(SHIBRPC_OK) {}
-    explicit ShibTargetException(ShibRpcStatus code, const char* msg, const shibboleth::IEntityDescriptor* provider);
-    explicit ShibTargetException(ShibRpcStatus code, const char* msg, const shibboleth::IRoleDescriptor* role=NULL);
-    
-    virtual ~ShibTargetException() throw () {}
-    virtual ShibRpcStatus which() const throw () { return m_code; }
-    virtual const char* what() const throw () { return m_msg.c_str(); }
-    virtual const char* syswho() const throw() { return m_providerId.c_str(); }
-    virtual const char* where() const throw () { return m_errorURL.c_str(); }
-    virtual const char* who() const throw () { return m_contact.c_str(); }
-    virtual const char* how() const throw () { return m_email.c_str(); }
-
-  private:
-    ShibRpcStatus m_code;
-    std::string m_msg;
-    std::string m_providerId;
-    std::string m_errorURL;
-    std::string m_contact;
-    std::string m_email;
-  };
-
-  class RPCErrorPriv;
-  class SHIBTARGET_EXPORTS RPCError
-  {
-  public:
-    RPCError();
-    RPCError(ShibRpcError* e);
-    RPCError(int s, const char* st);
-    RPCError(ShibTargetException &exp);
-    ~RPCError();
-
-    bool isError();
-    bool isRetryable();
-
-    // Return a set of strings that correspond to the error properties
-    const char* getType();
-    const char* getText();
-    const char* getDesc();
-    const char* getProviderId();
-    const char* getErrorURL();
-    const char* getContactName();
-    const char* getContactEmail();
-    int getCode();
-
-  private:
-    RPCErrorPriv* m_priv;
-  };
+    DECLARE_SAML_EXCEPTION(SHIBTARGET_EXPORTS,ListenerException,SAMLException);
 
     // Abstract APIs for access to configuration information
     
@@ -312,7 +256,7 @@ namespace shibtarget {
           std::string k = key, v = value;
           insert(k,v);
         }
-        void insert (RPCError& e);
+        void insert (saml::SAMLException& e);
 
         void clear () { m_map.clear(); }
 
@@ -329,11 +273,6 @@ namespace shibtarget {
         std::string m_generated;
     };
 
-  //******************************************************************************
-  //
-  // This is the interface you're looking for.
-  //
-
   class HTAccessInfo {
   public:
     class RequireLine {
@@ -535,8 +474,8 @@ namespace shibtarget {
     ShibTarget();
 
     // Currently wraps remoted interface.
-    // TODO: Move this functionality behind ISessionCache
-    RPCError* sessionNew(
+    // TODO: Move this functionality behind IListener
+    void sessionNew(
         int supported_profiles,
         const char* packet,
         const char* ip,
@@ -544,7 +483,7 @@ namespace shibtarget {
         std::string& target
         ) const;
 
-    RPCError* sessionGet(
+    void sessionGet(
         const char* cookie,
         const char* ip,
         ShibProfile& profile,
index fd78b2b..8e084aa 100644 (file)
@@ -95,32 +95,6 @@ shibrpc_ping_2_svc(int *argp, int *result, struct svc_req *rqstp)
   return TRUE;
 }
 
-// Functions to map errors into IDL-defined status structure
-
-void set_rpc_status(ShibRpcError *error, ShibRpcStatus status, const char* msg=NULL)
-{
-  error->status = status;
-  if (status) {
-    error->ShibRpcError_u.e.error = strdup(msg ? msg : "");
-    error->ShibRpcError_u.e.provider = strdup("");
-    error->ShibRpcError_u.e.url = strdup("");
-    error->ShibRpcError_u.e.contact = strdup("");
-    error->ShibRpcError_u.e.email = strdup("");
-  }
-}
-
-void set_rpc_status(ShibRpcError *error, ShibTargetException& exc)
-{
-  error->status = exc.which();
-  if (error->status) {
-    error->ShibRpcError_u.e.error = strdup(exc.what() ? exc.what() : "");
-    error->ShibRpcError_u.e.provider = strdup(exc.syswho() ? exc.syswho() : "");
-    error->ShibRpcError_u.e.url = strdup(exc.where() ? exc.where() : "");
-    error->ShibRpcError_u.e.contact = strdup(exc.who() ? exc.who() : "");
-    error->ShibRpcError_u.e.email = strdup(exc.how() ? exc.how() : "");
-  }
-}
-
 extern "C" bool_t
 shibrpc_get_session_2_svc(
     shibrpc_get_session_args_2 *argp,
@@ -128,162 +102,168 @@ shibrpc_get_session_2_svc(
     struct svc_req *rqstp
     )
 {
-  Category& log = get_category();
-  string ctx = get_threadid("get_session");
-  saml::NDC ndc(ctx);
+    Category& log = get_category();
+    string ctx = get_threadid("get_session");
+    saml::NDC ndc(ctx);
 
-  if (!argp || !result) {
-    log.error ("RPC Argument Error");
-    return FALSE;
-  }
+    if (!argp || !result) {
+        log.error ("RPC Argument Error");
+        return FALSE;
+    }
 
-  memset (result, 0, sizeof (*result));
-  result->provider_id = strdup("");
-  result->auth_statement = strdup("");
-  result->attr_response_pre = strdup("");
-  result->attr_response_post = strdup("");
+    memset (result, 0, sizeof (*result));
+    result->provider_id = strdup("");
+    result->auth_statement = strdup("");
+    result->attr_response_pre = strdup("");
+    result->attr_response_post = strdup("");
 
-  log.debug ("checking: %s@%s", argp->cookie, argp->client_addr);
+    log.debug ("checking: %s@%s", argp->cookie, argp->client_addr);
 
-  // See if the session exists...
+    // See if the session exists...
   
-  IConfig* conf=ShibTargetConfig::getConfig().getINI();
-  Locker locker(conf);
-  log.debug ("application: %s", argp->application_id);
-  const IApplication* app=conf->getApplication(argp->application_id);
-  if (!app) {
-    // Something's horribly wrong.
-    log.error("couldn't find application for session");
-    set_rpc_status(&result->status, SHIBRPC_UNKNOWN_ERROR, "Unable to locate application for session, deleted?");
-    return TRUE;
-  }
-
-  bool checkIPAddress=true;
-  int lifetime=0,timeout=0;
-  const IPropertySet* props=app->getPropertySet("Sessions");
-  if (props) {
-      pair<bool,unsigned int> p=props->getUnsignedInt("lifetime");
-      if (p.first)
-          lifetime = p.second;
-      p=props->getUnsignedInt("timeout");
-      if (p.first)
-          timeout = p.second;
-      pair<bool,bool> pcheck=props->getBool("checkAddress");
-      if (pcheck.first)
-          checkIPAddress = pcheck.second;
-  }
-    
-  ISessionCacheEntry* entry = conf->getSessionCache()->find(argp->cookie,app);
-
-  // If not, leave now..
-  if (!entry) {
-    log.debug ("Not found");
-    set_rpc_status(&result->status, SHIBRPC_NO_SESSION, "No session exists for this key value");
-    return TRUE;
-  }
-
-  // TEST the session...
-  try {
-    // Verify the address is the same
-    if (checkIPAddress) {
-      log.debug("Checking address against %s", entry->getClientAddress());
-      if (strcmp(argp->client_addr, entry->getClientAddress())) {
-        log.debug ("IP Address mismatch");
-        Metadata m(app->getMetadataProviders());
-        throw ShibTargetException(SHIBRPC_IPADDR_MISMATCH,
-            "Your IP address does not match the address recorded at the time the session was established.",
-            m.lookup(entry->getProviderId()));
-      }
+    IConfig* conf=ShibTargetConfig::getConfig().getINI();
+    Locker locker(conf);
+    log.debug ("application: %s", argp->application_id);
+    const IApplication* app=conf->getApplication(argp->application_id);
+    if (!app) {
+        // Something's horribly wrong.
+        log.error("couldn't find application for session");
+        SAMLException ex("Unable to locate application for session, deleted?");
+        ostringstream os;
+        os << ex;
+        result->status=strdup(os.str().c_str());
+        return TRUE;
     }
 
-    // and that the session is still valid...
-    if (!entry->isValid(lifetime,timeout)) {
-      log.debug ("Session expired");
-      Metadata m(app->getMetadataProviders());
-      throw ShibTargetException(SHIBRPC_SESSION_EXPIRED,
-        "Your session has expired, and you must re-authenticate.",
-        m.lookup(entry->getProviderId()));
+    bool checkIPAddress=true;
+    int lifetime=0,timeout=0;
+    const IPropertySet* props=app->getPropertySet("Sessions");
+    if (props) {
+        pair<bool,unsigned int> p=props->getUnsignedInt("lifetime");
+        if (p.first)
+            lifetime = p.second;
+        p=props->getUnsignedInt("timeout");
+        if (p.first)
+            timeout = p.second;
+        pair<bool,bool> pcheck=props->getBool("checkAddress");
+        if (pcheck.first)
+            checkIPAddress = pcheck.second;
+    }
+    
+    ISessionCacheEntry* entry = conf->getSessionCache()->find(argp->cookie,app);
+
+    // If not, leave now..
+    if (!entry) {
+        log.debug("session not found");
+        InvalidSessionException ex("No session exists for key value ($session_id)",namedparams(1,"session_id",argp->cookie));
+        ostringstream os;
+        os << ex;
+        result->status=strdup(os.str().c_str());
+        return TRUE;
     }
 
+    // TEST the session...
     try {
-      // Set profile and provider
-      result->profile = entry->getProfile();
-      free(result->provider_id);
-      result->provider_id = strdup(entry->getProviderId());
+        // Verify the address is the same
+        if (checkIPAddress) {
+            log.debug("Checking address against %s", entry->getClientAddress());
+            if (strcmp(argp->client_addr, entry->getClientAddress())) {
+                log.debug("client address mismatch");
+                InvalidSessionException ex(
+                    SESSION_E_ADDRESSMISMATCH,
+                    "Your IP address (%1) does not match the address recorded at the time the session was established.",
+                    params(1,argp->client_addr)
+                    );
+                Metadata m(app->getMetadataProviders());
+                annotateException(ex,m.lookup(entry->getProviderId())); // throws it
+            }
+        }
+
+        // and that the session is still valid...
+        if (!entry->isValid(lifetime,timeout)) {
+            log.debug("session expired");
+            InvalidSessionException ex(SESSION_E_EXPIRED, "Your session has expired, and you must re-authenticate.");
+            Metadata m(app->getMetadataProviders());
+            annotateException(ex,m.lookup(entry->getProviderId())); // throws it
+        }
+
+        // Set profile and provider
+        result->profile = entry->getProfile();
+        free(result->provider_id);
+        result->provider_id = strdup(entry->getProviderId());
      
-      // Now grab the serialized authentication statement and responses
-      ostringstream os;
-      os << *(entry->getAuthnStatement());
-      free(result->auth_statement);
-      result->auth_statement = strdup(os.str().c_str());
+        // Now grab the serialized authentication statement and responses
+        ostringstream os;
+        os << *(entry->getAuthnStatement());
+        free(result->auth_statement);
+        result->auth_statement = strdup(os.str().c_str());
       
-      ISessionCacheEntry::CachedResponse responses=entry->getResponse();
-      if (!responses.empty()) {
-          os.str("");
-          os << *responses.unfiltered;
-          free(result->attr_response_pre);
-          result->attr_response_pre = strdup(os.str().c_str());
-
-          os.str("");
-          os << *responses.filtered;
-          free(result->attr_response_post);
-          result->attr_response_post = strdup(os.str().c_str());
-      }
+        ISessionCacheEntry::CachedResponse responses=entry->getResponse();
+        if (!responses.empty()) {
+            os.str("");
+            os << *responses.unfiltered;
+            free(result->attr_response_pre);
+            result->attr_response_pre = strdup(os.str().c_str());
+
+            os.str("");
+            os << *responses.filtered;
+            free(result->attr_response_post);
+            result->attr_response_post = strdup(os.str().c_str());
+        }
     }
     catch (SAMLException &e) {
-      log.error ("caught SAML exception: %s", e.what());
-      ostringstream os;
-      os << e;
-      Metadata m(app->getMetadataProviders());
-      throw ShibTargetException(SHIBRPC_SAML_EXCEPTION, os.str().c_str(), m.lookup(entry->getProviderId()));
+        entry->unlock();
+        log.error("caught SAML exception: %s", e.what());
+        conf->getSessionCache()->remove(argp->cookie);
+        ostringstream os;
+        os << e;
+        result->status = strdup(os.str().c_str());
+      
+        // Transaction Logging
+        STConfig& stc=static_cast<STConfig&>(ShibTargetConfig::getConfig());
+        stc.getTransactionLog().infoStream() <<
+            "Destroyed invalid session (ID: " <<
+                argp->cookie <<
+            ") with (applicationId: " <<
+                argp->application_id <<
+            "), request was from (ClientAddress: " <<
+                argp->client_addr <<
+            ")";
+        stc.releaseTransactionLog();
+        return TRUE;
     }
-  }
-  catch (ShibTargetException &e) {
-      entry->unlock();
-      log.error ("FAILED: %s", e.what());
-      conf->getSessionCache()->remove(argp->cookie);
-      set_rpc_status(&result->status, e);
-      // Transaction Logging
-      STConfig& stc=static_cast<STConfig&>(ShibTargetConfig::getConfig());
-      stc.getTransactionLog().infoStream() <<
-          "Destroyed invalid session (ID: " <<
-              argp->cookie <<
-          ") with (applicationId: " <<
-              argp->application_id <<
-          "), request was from (ClientAddress: " <<
-              argp->client_addr <<
-          ")";
-      stc.releaseTransactionLog();
-      return TRUE;
-  }
 #ifndef _DEBUG
-  catch (...) {
-      entry->unlock();
-      log.error ("Unknown exception");
-      conf->getSessionCache()->remove(argp->cookie);
-      set_rpc_status(&result->status, SHIBRPC_UNKNOWN_ERROR, "An unknown exception occurred");
-      // Transaction Logging
-      STConfig& stc=static_cast<STConfig&>(ShibTargetConfig::getConfig());
-      stc.getTransactionLog().infoStream() <<
-          "Destroyed invalid session (ID: " <<
-              argp->cookie <<
-          ") with (applicationId: " <<
-              argp->application_id <<
-          "), request was from (ClientAddress: " <<
-              argp->client_addr <<
-          ")";
-      stc.releaseTransactionLog();
-      return TRUE;
-  }
+    catch (...) {
+        log.error("caught unknown exception");
+        InvalidSessionException ex("An unexpected error occurred while validating your session, and you must re-authenticate.");
+        Metadata m(app->getMetadataProviders());
+        annotateException(ex,m.lookup(entry->getProviderId()),false);
+        entry->unlock();
+        conf->getSessionCache()->remove(argp->cookie);
+        ostringstream os;
+        os << ex;
+        result->status = strdup(os.str().c_str());
+
+        // Transaction Logging
+        STConfig& stc=static_cast<STConfig&>(ShibTargetConfig::getConfig());
+        stc.getTransactionLog().infoStream() <<
+            "Destroyed invalid session (ID: " <<
+                argp->cookie <<
+            ") with (applicationId: " <<
+                argp->application_id <<
+            "), request was from (ClientAddress: " <<
+                argp->client_addr <<
+            ")";
+        stc.releaseTransactionLog();
+        return TRUE;
+    }
 #endif
 
-  // Ok, just release it.
-  entry->unlock();
-
-  // ok, we've succeeded..
-  set_rpc_status(&result->status, SHIBRPC_OK);
-  log.debug ("session ok");
-  return TRUE;
+    // Ok, just release it.
+    entry->unlock();
+    log.debug ("session ok");
+    result->status=strdup("");
+    return TRUE;
 }
 
 extern "C" bool_t
@@ -293,266 +273,243 @@ shibrpc_new_session_2_svc(
     struct svc_req *rqstp
     )
 {
-  Category& log = get_category();
-  string ctx=get_threadid("new_session");
-  saml::NDC ndc(ctx);
-
-  if (!argp || !result) {
-    log.error ("Invalid RPC Arguments");
-    return FALSE;
-  }
+    Category& log = get_category();
+    string ctx=get_threadid("new_session");
+    saml::NDC ndc(ctx);
 
-  // Initialize the result structure
-  memset (result, 0, sizeof(*result));
-  result->cookie = strdup ("");
-  result->target = strdup ("");
+    if (!argp || !result) {
+        log.error ("Invalid RPC Arguments");
+        return FALSE;
+    }
 
-  log.debug ("creating session for %s", argp->client_addr);
-  log.debug ("recipient: %s", argp->recipient);
-  log.debug ("application: %s", argp->application_id);
+    // Initialize the result structure
+    memset (result, 0, sizeof(*result));
+    result->cookie = strdup ("");
+    result->target = strdup ("");
+
+    log.debug ("creating session for %s", argp->client_addr);
+    log.debug ("recipient: %s", argp->recipient);
+    log.debug ("application: %s", argp->application_id);
+
+    auto_ptr_XMLCh recipient(argp->recipient);
+
+    // Access the application config.
+    IConfig* conf=ShibTargetConfig::getConfig().getINI();
+    Locker locker(conf);
+    const IApplication* app=conf->getApplication(argp->application_id);
+    if (!app) {
+        // Something's horribly wrong. Flush the session.
+        log.error ("couldn't find application for session");
+        SAMLException ex("Unable to locate application for session, deleted?");
+        ostringstream os;
+        os << ex;
+        result->status=strdup(os.str().c_str());
+        return TRUE;
+    }
 
-  auto_ptr_XMLCh recipient(argp->recipient);
+    bool checkIPAddress=true;
+    const IPropertySet* props=app->getPropertySet("Sessions");
+    if (props) {
+        pair<bool,bool> pcheck=props->getBool("checkAddress");
+        if (pcheck.first)
+            checkIPAddress = pcheck.second;
+    }
 
-  SAMLResponse* r = NULL;
-  const SAMLAuthenticationStatement* auth_st = NULL;
-  XMLCh* origin = NULL;
+    pair<bool,bool> checkReplay=pair<bool,bool>(false,false);
+    props=app->getPropertySet("Sessions");
+    if (props)
+        checkReplay=props->getBool("checkReplay");
  
-  // Access the application config.
-  IConfig* conf=ShibTargetConfig::getConfig().getINI();
-  Locker locker(conf);
-  const IApplication* app=conf->getApplication(argp->application_id);
-  if (!app) {
-      // Something's horribly wrong. Flush the session.
-      log.error ("couldn't find application for session");
-      set_rpc_status(&result->status, SHIBRPC_INTERNAL_ERROR, "Unable to locate application for session, deleted?");
-      return TRUE;
-  }
-
-  bool checkIPAddress=true;
-  const IPropertySet* props=app->getPropertySet("Sessions");
-  if (props) {
-      pair<bool,bool> pcheck=props->getBool("checkAddress");
-      if (pcheck.first)
-          checkIPAddress = pcheck.second;
-  }
-
-  pair<bool,bool> checkReplay=pair<bool,bool>(false,false);
-  props=app->getPropertySet("Sessions");
-  if (props)
-      checkReplay=props->getBool("checkReplay");
-  const IRoleDescriptor* role=NULL;
-  Metadata m(app->getMetadataProviders());
-  SAMLBrowserProfile::BrowserProfileResponse bpr;
-  try
-  {
-    if (!app)
-        // Something's horribly wrong.
-        throw ShibTargetException(SHIBRPC_INTERNAL_ERROR,"Unable to locate application configuration, deleted?");
-      
-    try
-    {
-      auto_ptr<SAMLBrowserProfile::ArtifactMapper> artifactMapper(app->getArtifactMapper());
+    const IRoleDescriptor* role=NULL;
+    Metadata m(app->getMetadataProviders());
+    SAMLBrowserProfile::BrowserProfileResponse bpr;
+    try {
+        auto_ptr<SAMLBrowserProfile::ArtifactMapper> artifactMapper(app->getArtifactMapper());
       
-      // Try and run the profile.
-      log.debug ("Executing browser profile...");
-      bpr=app->getBrowserProfile()->receive(
-        &origin,
-        argp->packet,
-        recipient.get(),
-        SAMLBrowserProfile::Post | SAMLBrowserProfile::Artifact,
-        (!checkReplay.first || checkReplay.second) ? conf->getReplayCache() : NULL,
-        artifactMapper.get()
-        );
-
-      // Blow it away to clear any locks that might be held.
-      delete artifactMapper.release();
-
-      // Try and map to metadata for support purposes.
-      const IEntityDescriptor* provider=m.lookup(origin);
-      if (provider) {
-          const IIDPSSODescriptor* IDP=provider->getIDPSSODescriptor(saml::XML::SAML11_PROTOCOL_ENUM);
-          role=IDP;
-      }
-      // This can't really happen, since the profile must have found a role.
-      if (!role)
-        throw ShibTargetException(SHIBRPC_INTERNAL_ERROR,
-            "Unable to locate role-specific metadata for identity provider", provider);
+        // Try and run the profile.
+        log.debug("executing browser profile...");
+        int allowed = 0;
+        if (argp->supported_profiles & SAML11_POST)
+            allowed |= SAMLBrowserProfile::Post;
+        if (argp->supported_profiles & SAML11_ARTIFACT)
+            allowed |= SAMLBrowserProfile::Artifact;
+        bpr=app->getBrowserProfile()->receive(
+            argp->packet,
+            recipient.get(),
+            allowed,
+            (!checkReplay.first || checkReplay.second) ? conf->getReplayCache() : NULL,
+            artifactMapper.get()
+            );
+
+        // Blow it away to clear any locks that might be held.
+        delete artifactMapper.release();
+
+        // Try and map to metadata (again).
+        // Once the metadata layer is in the SAML core, the repetition should be fixed.
+        const IEntityDescriptor* provider=m.lookup(bpr.assertion->getIssuer());
+        if (!provider && bpr.authnStatement->getSubject()->getNameIdentifier()->getNameQualifier())
+            provider=m.lookup(bpr.authnStatement->getSubject()->getNameIdentifier()->getNameQualifier());
+        if (provider) {
+            const IIDPSSODescriptor* IDP=provider->getIDPSSODescriptor(saml::XML::SAML11_PROTOCOL_ENUM);
+            role=IDP;
+        }
+        
+        // This isn't likely, since the profile must have found a role.
+        if (!role) {
+            MetadataException ex("Unable to locate role-specific metadata for identity provider.");
+            annotateException(ex,provider); // throws it
+        }
     
-      // Maybe verify the origin address....
-      if (checkIPAddress) {
-        log.debug ("verify client address");
-
-        // Verify the client address exists
-        const XMLCh* ip = bpr.authnStatement->getSubjectIP();
-        if (ip && *ip) {
-            // Verify the client address matches authentication
-            auto_ptr_char this_ip(ip);
-            if (strcmp(argp->client_addr, this_ip.get()))
-                throw ShibTargetException(SHIBRPC_IPADDR_MISMATCH,
-                       "Your client's current IP address differs from the one used when you authenticated "
-                    "to your identity provider. To correct this problem, you may need to bypass a proxy server. "
-                    "Please contact your local support staff or help desk for assistance.",
-                                    role);
+        // Maybe verify the origin address....
+        if (checkIPAddress) {
+            log.debug("verify client address");
+            // Verify the client address exists
+            const XMLCh* ip = bpr.authnStatement->getSubjectIP();
+            if (ip && *ip) {
+                // Verify the client address matches authentication
+                auto_ptr_char this_ip(ip);
+                if (strcmp(argp->client_addr, this_ip.get())) {
+                    FatalProfileException ex(
+                        SESSION_E_ADDRESSMISMATCH,
+                       "Your client's current address ($1) differs from the one used when you authenticated "
+                        "to your identity provider. To correct this problem, you may need to bypass a proxy server. "
+                        "Please contact your local support staff or help desk for assistance.",
+                        params(1,argp->client_addr)
+                        );
+                    annotateException(ex,role); // throws it
+                }
+            }
         }
-      }
       
-      // Verify condition(s) on authentication assertion.
-      // Attribute assertions get filtered later, essentially just like an AAP.
-      Iterator<SAMLCondition*> conditions=bpr.assertion->getConditions();
-      while (conditions.hasNext()) {
-        SAMLCondition* cond=conditions.next();
-        const SAMLAudienceRestrictionCondition* ac=dynamic_cast<const SAMLAudienceRestrictionCondition*>(cond);
-        if (!ac) {
-            ostringstream os;
-            os << *cond;
-            log.error("Unrecognized Condition in authentication assertion (%s), tossing it.",os.str().c_str());
-            throw FatalProfileException("Unable to start session due to unrecognized condition in authentication assertion.");
+        // Verify condition(s) on authentication assertion.
+        // Attribute assertions get filtered later, essentially just like an AAP.
+        Iterator<SAMLCondition*> conditions=bpr.assertion->getConditions();
+        while (conditions.hasNext()) {
+            SAMLCondition* cond=conditions.next();
+            const SAMLAudienceRestrictionCondition* ac=dynamic_cast<const SAMLAudienceRestrictionCondition*>(cond);
+            if (!ac) {
+                ostringstream os;
+                os << *cond;
+                log.error("Unrecognized Condition in authentication assertion (%s), tossing it.",os.str().c_str());
+                FatalProfileException ex("Unable to create session due to unrecognized condition in authentication assertion.");
+                annotateException(ex,role); // throws it
+            }
+            else if (!ac->eval(app->getAudiences())) {
+                ostringstream os;
+                os << *ac;
+                log.error("Unacceptable AudienceRestrictionCondition in authentication assertion (%s), tossing it.",os.str().c_str());
+                FatalProfileException ex("Unable to create session due to unacceptable AudienceRestrictionCondition in authentication assertion.");
+                annotateException(ex,role); // throws it
+            }
         }
-        else if (!ac->eval(app->getAudiences())) {
-            ostringstream os;
-            os << *ac;
-            log.error("Unacceptable AudienceRestrictionCondition in authentication assertion (%s), tossing it.",os.str().c_str());
-            throw FatalProfileException("Unable to start session due to unacceptable AudienceRestrictionCondition in authentication assertion.");
-        }
-      }
-    }
-    catch (ReplayedAssertionException& e) {
-      // Specific case where we have an error code.
-      if (!role && origin) {
-          // Try and map to metadata for support purposes.
-          const IEntityDescriptor* provider=m.lookup(origin);
-          if (provider) {
-              const IIDPSSODescriptor* IDP=provider->getIDPSSODescriptor(saml::XML::SAML11_PROTOCOL_ENUM);
-              role=IDP;
-          }
-      }
-      throw ShibTargetException(SHIBRPC_ASSERTION_REPLAYED, e.what(), role);
     }
     catch (SAMLException& e) {
-      log.error ("caught SAML exception: %s", e.what());
-      ostringstream os;
-      os << e;
-      if (!role && origin) {
-          // Try and map to metadata for support purposes.
-          const IEntityDescriptor* provider=m.lookup(origin);
-          if (provider) {
-              const IIDPSSODescriptor* IDP=provider->getIDPSSODescriptor(saml::XML::SAML11_PROTOCOL_ENUM);
-              role=IDP;
-          }
-      }
-      throw ShibTargetException (SHIBRPC_SAML_EXCEPTION, os.str().c_str(), role);
+        bpr.clear();
+        log.error("caught SAML exception: %s", e.what());
+        ostringstream os;
+        os << e;
+        result->status = strdup(os.str().c_str());
+        return TRUE;
     }
-  }
-  catch (ShibTargetException& e) {
-    log.error ("FAILED: %s", e.what());
-    bpr.clear();
-    if (origin) XMLString::release(&origin);
-    set_rpc_status(&result->status, e);
-    return TRUE;
-  }
 #ifndef _DEBUG
-  catch (...) {
-    log.error ("Unknown error");
-    bpr.clear();
-    if (origin) XMLString::release(&origin);
-    set_rpc_status(&result->status, SHIBRPC_UNKNOWN_ERROR, "An unknown exception occurred");
-    return TRUE;
-  }
+    catch (...) {
+        log.error("unknown error");
+        bpr.clear();
+        SAMLException e("An unexpected error occurred while creating your session.");
+        annotateException(e,role,false);
+        ostringstream os;
+        os << e;
+        result->status = strdup(os.str().c_str());
+        return TRUE;
+    }
 #endif
 
-  // It passes all our tests -- create a new session.
-  log.info ("Creating new session");
-
-  // Create a new session key.
-  string cookie = conf->getSessionCache()->generateKey();
-
-  // Are attributes present?
-  bool attributesPushed=false;
-  Iterator<SAMLAssertion*> assertions=bpr.response->getAssertions();
-  while (!attributesPushed && assertions.hasNext()) {
-      Iterator<SAMLStatement*> statements=assertions.next()->getStatements();
-      while (!attributesPushed && statements.hasNext()) {
-          if (dynamic_cast<SAMLAttributeStatement*>(statements.next()))
-            attributesPushed=true;
-      }
-  }
-  
-  // Insertion into cache might fail.
-  auto_ptr_char oname(origin);
-  SAMLAuthenticationStatement* as=NULL;
-  try {
-      as=static_cast<SAMLAuthenticationStatement*>(bpr.authnStatement->clone());
-      // TODO: we need to extract the Issuer and propagate that around as the origin site along
-      // with the statement and attribute assertions.
-      conf->getSessionCache()->insert(
-        cookie.c_str(),
-        app,
-        argp->client_addr,
-        SAML_11_POST,       // TODO: need to vary this
-        oname.get(),
-        as,
-        (attributesPushed ? bpr.response : NULL),
-        role
-        );
-  }
-  catch (SAMLException& e) {
-      log.error ("caught SAML exception during cache insertion: %s", e.what());
-      delete as;
-      ostringstream os;
-      os << e;
-      bpr.clear();
-      if (origin) XMLString::release(&origin);
-      ShibTargetException ex(SHIBRPC_SAML_EXCEPTION, os.str().c_str(), role);
-      set_rpc_status(&result->status, ex);
-      return TRUE;
-  }
+    // It passes all our tests -- create a new session.
+    log.info("creating new session");
+
+    // Create a new session key.
+    string cookie = conf->getSessionCache()->generateKey();
+
+    // Are attributes present?
+    bool attributesPushed=false;
+    Iterator<SAMLAssertion*> assertions=bpr.response->getAssertions();
+    while (!attributesPushed && assertions.hasNext()) {
+        Iterator<SAMLStatement*> statements=assertions.next()->getStatements();
+        while (!attributesPushed && statements.hasNext()) {
+            if (dynamic_cast<SAMLAttributeStatement*>(statements.next()))
+                attributesPushed=true;
+        }
+    }
+
+    auto_ptr_char oname(role->getEntityDescriptor()->getId());
+    auto_ptr_char hname(bpr.authnStatement->getSubject()->getNameIdentifier()->getName());
+
+    try {
+        // Insert into cache.
+        auto_ptr<SAMLAuthenticationStatement> as(static_cast<SAMLAuthenticationStatement*>(bpr.authnStatement->clone()));
+        conf->getSessionCache()->insert(
+            cookie.c_str(),
+            app,
+            argp->client_addr,
+            (bpr.profile==SAMLBrowserProfile::Post) ? SAML11_POST : SAML11_ARTIFACT,
+            oname.get(),
+            as.get(),
+            (attributesPushed ? bpr.response : NULL),
+            role
+            );
+        as.release();   // owned by cache now
+    }
+    catch (SAMLException& e) {
+        bpr.clear();
+        log.error("caught SAML exception: %s", e.what());
+        ostringstream os;
+        os << e;
+        result->status = strdup(os.str().c_str());
+        return TRUE;
+    }
 #ifndef _DEBUG
-  catch (...) {
-      log.error ("caught unknown exception during cache insertion");
-      delete as;
-      bpr.clear();
-      if (origin) XMLString::release(&origin);
-      set_rpc_status(&result->status, SHIBRPC_UNKNOWN_ERROR, "An unknown exception occurred");
-      return TRUE;
-  }
+    catch (...) {
+        log.error("unknown error");
+        bpr.clear();
+        SAMLException e("An unexpected error occurred while creating your session.");
+        annotateException(e,role,false);
+        ostringstream os;
+        os << e;
+        result->status = strdup(os.str().c_str());
+        return TRUE;
+    }
 #endif
-    
-  // And let the user know.
-  if (result->cookie) free(result->cookie);
-  if (result->target) free(result->target);
-  result->cookie = strdup(cookie.c_str());
-  result->target = strdup(bpr.TARGET.c_str());
-  set_rpc_status(&result->status, SHIBRPC_OK);
-
-  // Maybe delete the response...
-  if (!attributesPushed)
-    bpr.clear();
-
-  log.debug("new session id: %s", cookie.c_str());
-  
-  // Transaction Logging
-  STConfig& stc=static_cast<STConfig&>(ShibTargetConfig::getConfig());
-  auto_ptr_char hname(as->getSubject()->getNameIdentifier()->getName());
-  stc.getTransactionLog().infoStream() <<
-    "New session (ID: " <<
-        result->cookie <<
-    ") with (applicationId: " <<
-        argp->application_id <<
-    ") for principal from (IdP: " <<
-        oname.get() <<
-    ") at (ClientAddress: " <<
-        argp->client_addr <<
-    ") with (NameIdentifier: " <<
-        hname.get() <<
-    ")";
-
-  stc.releaseTransactionLog();
-
-  // Delete the origin...
-  if (origin) XMLString::release(&origin);
 
-  return TRUE;
+    // And let the user know.
+    if (result->cookie) free(result->cookie);
+    if (result->target) free(result->target);
+    result->cookie = strdup(cookie.c_str());
+    result->target = strdup(bpr.TARGET.c_str());
+    result->status = strdup("");
+
+    // Maybe delete the response...
+    if (!attributesPushed)
+        bpr.clear();
+
+    log.debug("new session id: %s", cookie.c_str());
+  
+    // Transaction Logging
+    STConfig& stc=static_cast<STConfig&>(ShibTargetConfig::getConfig());
+    stc.getTransactionLog().infoStream() <<
+        "New session (ID: " <<
+            result->cookie <<
+        ") with (applicationId: " <<
+            argp->application_id <<
+        ") for principal from (IdP: " <<
+            oname.get() <<
+        ") at (ClientAddress: " <<
+            argp->client_addr <<
+        ") with (NameIdentifier: " <<
+            hname.get() <<
+        ")";
+
+    stc.releaseTransactionLog();
+    return TRUE;
 }
 
 extern "C" int
index 661d7b9..11f267c 100644 (file)
 
 
 bool_t
-xdr_ShibRpcStatus (XDR *xdrs, ShibRpcStatus *objp)
-{
-       register int32_t *buf;
-
-        if (!xdr_enum (xdrs, (enum_t *) objp))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_ShibRpcErr (XDR *xdrs, ShibRpcErr *objp)
-{
-       register int32_t *buf;
-
-        if (!xdr_string (xdrs, &objp->error, ~0))
-                return FALSE;
-        if (!xdr_string (xdrs, &objp->provider, ~0))
-                return FALSE;
-        if (!xdr_string (xdrs, &objp->url, ~0))
-                return FALSE;
-        if (!xdr_string (xdrs, &objp->contact, ~0))
-                return FALSE;
-        if (!xdr_string (xdrs, &objp->email, ~0))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_ShibRpcError (XDR *xdrs, ShibRpcError *objp)
-{
-       register int32_t *buf;
-
-        if (!xdr_ShibRpcStatus (xdrs, &objp->status))
-                return FALSE;
-       switch (objp->status) {
-       case SHIBRPC_OK:
-               break;
-       default:
-                if (!xdr_ShibRpcErr (xdrs, &objp->ShibRpcError_u.e))
-                        return FALSE;
-               break;
-       }
-       return TRUE;
-}
-
-bool_t
 xdr_ShibProfile (XDR *xdrs, ShibProfile *objp)
 {
        register int32_t *buf;
@@ -90,7 +44,7 @@ xdr_shibrpc_new_session_ret_2 (XDR *xdrs, shibrpc_new_session_ret_2 *objp)
 {
        register int32_t *buf;
 
-        if (!xdr_ShibRpcError (xdrs, &objp->status))
+        if (!xdr_string (xdrs, &objp->status, ~0))
                 return FALSE;
         if (!xdr_string (xdrs, &objp->target, ~0))
                 return FALSE;
@@ -118,7 +72,7 @@ xdr_shibrpc_get_session_ret_2 (XDR *xdrs, shibrpc_get_session_ret_2 *objp)
 {
        register int32_t *buf;
 
-        if (!xdr_ShibRpcError (xdrs, &objp->status))
+        if (!xdr_string (xdrs, &objp->status, ~0))
                 return FALSE;
         if (!xdr_ShibProfile (xdrs, &objp->profile))
                 return FALSE;
index ac4cd59..f39c43d 100644 (file)
@@ -17,46 +17,13 @@ extern "C" {
 #endif
 
 
-enum ShibRpcStatus {
-       SHIBRPC_OK = 0,
-       SHIBRPC_UNKNOWN_ERROR = 1,
-       SHIBRPC_INTERNAL_ERROR = 2,
-       SHIBRPC_XML_EXCEPTION = 3,
-       SHIBRPC_SAX_EXCEPTION = 4,
-       SHIBRPC_SAML_EXCEPTION = 5,
-       SHIBRPC_NO_SESSION = 10,
-       SHIBRPC_SESSION_EXPIRED = 11,
-       SHIBRPC_IPADDR_MISMATCH = 12,
-       SHIBRPC_IPADDR_MISSING = 20,
-       SHIBRPC_RESPONSE_MISSING = 21,
-       SHIBRPC_ASSERTION_REPLAYED = 22,
-};
-typedef enum ShibRpcStatus ShibRpcStatus;
-
-struct ShibRpcErr {
-       char *error;
-       char *provider;
-       char *url;
-       char *contact;
-       char *email;
-};
-typedef struct ShibRpcErr ShibRpcErr;
-
-struct ShibRpcError {
-       ShibRpcStatus status;
-       union {
-               ShibRpcErr e;
-       } ShibRpcError_u;
-};
-typedef struct ShibRpcError ShibRpcError;
-
 enum ShibProfile {
        PROFILE_UNSPECIFIED = 0,
-       SAML_10_POST = 1,
-       SAML_10_ARTIFACT = 2,
-       SAML_11_POST = 4,
-       SAML_11_ARTIFACT = 8,
-       SAML_20_SSO = 16,
+       SAML10_POST = 1,
+       SAML10_ARTIFACT = 2,
+       SAML11_POST = 4,
+       SAML11_ARTIFACT = 8,
+       SAML20_SSO = 16,
 };
 typedef enum ShibProfile ShibProfile;
 
@@ -70,7 +37,7 @@ struct shibrpc_new_session_args_2 {
 typedef struct shibrpc_new_session_args_2 shibrpc_new_session_args_2;
 
 struct shibrpc_new_session_ret_2 {
-       ShibRpcError status;
+       char *status;
        char *target;
        char *cookie;
 };
@@ -84,7 +51,7 @@ struct shibrpc_get_session_args_2 {
 typedef struct shibrpc_get_session_args_2 shibrpc_get_session_args_2;
 
 struct shibrpc_get_session_ret_2 {
-       ShibRpcError status;
+       char *status;
        ShibProfile profile;
        char *provider_id;
        char *auth_statement;
@@ -124,9 +91,6 @@ extern int shibrpc_prog_2_freeresult ();
 /* the xdr functions */
 
 #if defined(__STDC__) || defined(__cplusplus)
-extern  bool_t xdr_ShibRpcStatus (XDR *, ShibRpcStatus*);
-extern  bool_t xdr_ShibRpcErr (XDR *, ShibRpcErr*);
-extern  bool_t xdr_ShibRpcError (XDR *, ShibRpcError*);
 extern  bool_t xdr_ShibProfile (XDR *, ShibProfile*);
 extern  bool_t xdr_shibrpc_new_session_args_2 (XDR *, shibrpc_new_session_args_2*);
 extern  bool_t xdr_shibrpc_new_session_ret_2 (XDR *, shibrpc_new_session_ret_2*);
@@ -134,9 +98,6 @@ extern  bool_t xdr_shibrpc_get_session_args_2 (XDR *, shibrpc_get_session_args_2
 extern  bool_t xdr_shibrpc_get_session_ret_2 (XDR *, shibrpc_get_session_ret_2*);
 
 #else /* K&R C */
-extern bool_t xdr_ShibRpcStatus ();
-extern bool_t xdr_ShibRpcErr ();
-extern bool_t xdr_ShibRpcError ();
 extern bool_t xdr_ShibProfile ();
 extern bool_t xdr_shibrpc_new_session_args_2 ();
 extern bool_t xdr_shibrpc_new_session_ret_2 ();
index 4914126..00977cd 100644 (file)
 %
 #endif
 
-enum ShibRpcStatus {
-  SHIBRPC_OK = 0,
-  SHIBRPC_UNKNOWN_ERROR = 1,
-  SHIBRPC_INTERNAL_ERROR = 2,
-  SHIBRPC_XML_EXCEPTION = 3,
-  SHIBRPC_SAX_EXCEPTION = 4,
-  SHIBRPC_SAML_EXCEPTION = 5,
-
-  /* session_is_valid errors */
-  SHIBRPC_NO_SESSION = 10,
-  SHIBRPC_SESSION_EXPIRED = 11,
-  SHIBRPC_IPADDR_MISMATCH = 12,
-
-  /* new_session errors */
-  SHIBRPC_IPADDR_MISSING = 20,
-  SHIBRPC_RESPONSE_MISSING = 21,
-  SHIBRPC_ASSERTION_REPLAYED = 22
-
-  /* get_attrs errors */
-};
-
-/* Hold an error, providerId, and support data */
-struct ShibRpcErr {
-  string       error<>;
-  string       provider<>;
-  string       url<>;
-  string       contact<>;
-  string       email<>;
-};
-
-/* A type for RPC Errors */
-union ShibRpcError switch(ShibRpcStatus status) {
- case SHIBRPC_OK:
-   void;
- default:
-   ShibRpcErr  e;
-};
-
 /* enumerate profiles/bindings to support */
 enum ShibProfile {
   PROFILE_UNSPECIFIED = 0,
-  SAML_10_POST = 1,
-  SAML_10_ARTIFACT = 2,
-  SAML_11_POST = 4,
-  SAML_11_ARTIFACT = 8,
-  SAML_20_SSO = 16
+  SAML10_POST = 1,
+  SAML10_ARTIFACT = 2,
+  SAML11_POST = 4,
+  SAML11_ARTIFACT = 8,
+  SAML20_SSO = 16
 };
 
 /* function argument and response structures */
@@ -74,7 +36,7 @@ struct shibrpc_new_session_args_2 {
 };
 
 struct shibrpc_new_session_ret_2 {
-  ShibRpcError status;
+  string       status<>;                               /* empty string or a SAMLException */
   string       target<>;                               /* profile-specific state token from client */
   string       cookie<>;                               /* session key manufactured for client */
 };
@@ -86,7 +48,7 @@ struct shibrpc_get_session_args_2 {
 };
 
 struct shibrpc_get_session_ret_2 {
-  ShibRpcError status;
+  string               status<>;                               /* empty string or a SAMLException */
   ShibProfile  profile;                                /* profile used in creating session */
   string               provider_id<>;                  /* authenticating IdP */
   string               auth_statement<>;               /* SAML authn statement */
index 602276b..8588ee2 100644 (file)
@@ -95,6 +95,10 @@ SOURCE=.\ArtifactMapper.cpp
 # End Source File
 # Begin Source File
 
+SOURCE=.\hresult.h
+# End Source File
+# Begin Source File
+
 SOURCE=.\internal.h
 # End Source File
 # Begin Source File
@@ -119,10 +123,6 @@ SOURCE=".\shib-mlp.cpp"
 # End Source File
 # Begin Source File
 
-SOURCE=".\shib-rpcerror.cpp"
-# End Source File
-# Begin Source File
-
 SOURCE=".\shib-rpchandle.cpp"
 # End Source File
 # Begin Source File