Options for per-content error handling.
[shibboleth/sp.git] / shibsp / ServiceProvider.cpp
index 3a4bb6d..c4b70b8 100644 (file)
@@ -49,8 +49,7 @@ namespace shibsp {
     {
         if (mayRedirect) {
             // Check for redirection on errors instead of template.
-            const PropertySet* sessions=app ? app->getPropertySet("Sessions") : NULL;
-            pair<bool,const char*> redirectErrors = sessions ? sessions->getString("redirectErrors") : pair<bool,const char*>(false,NULL);
+            pair<bool,const char*> redirectErrors = app ? app->getString("redirectErrors") : pair<bool,const char*>(false,NULL);
             if (redirectErrors.first) {
                 string loc(redirectErrors.second);
                 loc = loc + '?' + tp.toQueryString();
@@ -62,23 +61,37 @@ namespace shibsp {
         request.setResponseHeader("Expires","01-Jan-1997 12:00:00 GMT");
         request.setResponseHeader("Cache-Control","private,no-store,no-cache");
     
+        // Error templates come from the request's settings or from the Errors property set.
+        pair<bool,const char*> pathname = pair<bool,const char*>(false,NULL);
+        try {
+            RequestMapper::Settings settings = request.getRequestSettings();
+            string pagename(page);
+            pagename += "Error";
+            pathname = settings.first->getString(pagename.c_str());
+        }
+        catch (exception& ex) {
+            request.log(SPRequest::SPError, ex.what());
+        }
+
+        // Nothing for request, so check app properties.
         const PropertySet* props=app ? app->getPropertySet("Errors") : NULL;
-        if (props) {
-            pair<bool,const char*> p=props->getString(page);
-            if (p.first) {
-                ifstream infile(p.second);
-                if (infile) {
-                    tp.setPropertySet(props);
-                    stringstream str;
-                    XMLToolingConfig::getConfig().getTemplateEngine()->run(infile, str, tp, tp.getRichException());
-                    return request.sendResponse(str);
-                }
-            }
-            else if (!strcmp(page,"access")) {
-                istringstream msg("Access Denied");
-                return request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_FORBIDDEN);
+        if (!pathname.first && props)
+            pathname=props->getString(page);
+
+        if (pathname.first) {
+            ifstream infile(pathname.second);
+            if (infile) {
+                tp.setPropertySet(props);
+                stringstream str;
+                XMLToolingConfig::getConfig().getTemplateEngine()->run(infile, str, tp, tp.getRichException());
+                return request.sendResponse(str);
             }
         }
+        
+        if (!strcmp(page,"access")) {
+            istringstream msg("Access Denied");
+            return request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_FORBIDDEN);
+        }
     
         string errstr = string("sendError could not process error template (") + page + ")";
         request.log(SPRequest::SPError, errstr);
@@ -87,12 +100,13 @@ namespace shibsp {
     }
     
     void SHIBSP_DLLLOCAL clearHeaders(SPRequest& request) {
+        request.clearHeader("Shib-Session-ID", "HTTP_SHIB_SESSION_ID");
         request.clearHeader("Shib-Identity-Provider", "HTTP_SHIB_IDENTITY_PROVIDER");
         request.clearHeader("Shib-Authentication-Method", "HTTP_SHIB_AUTHENTICATION_METHOD");
         request.clearHeader("Shib-AuthnContext-Class", "HTTP_SHIB_AUTHNCONTEXT_CLASS");
         request.clearHeader("Shib-AuthnContext-Decl", "HTTP_SHIB_AUTHNCONTEXT_DECL");
-        request.clearHeader("Shib-Attributes", "HTTP_SHIB_ATTRIBUTES");
         request.clearHeader("Shib-Assertion-Count", "HTTP_SHIB_ASSERTION_COUNT");
+        request.clearHeader("REMOTE_USER", "HTTP_REMOTE_USER");
         //request.clearHeader("Shib-Application-ID");   handle inside app method
         request.getApplication().clearAttributeHeaders(request);
     }
@@ -334,6 +348,7 @@ pair<bool,long> ServiceProvider::doExport(SPRequest& request, bool requireSessio
         }
         
         request.setHeader("Shib-Application-ID", app->getId());
+        request.setHeader("Shib-Session-ID", session->getID());
 
         // Export the IdP name and Authn method/context info.
         const char* hval = session->getEntityID();
@@ -358,8 +373,12 @@ pair<bool,long> ServiceProvider::doExport(SPRequest& request, bool requireSessio
             else {
                 const URLEncoder* encoder = XMLToolingConfig::getConfig().getURLEncoder();
                 string exportName = "Shib-Assertion-00";
-                const char* handlerURL=request.getHandlerURL(targetURL.c_str());
-                string baseURL = string(handlerURL) + exportLocation.second + "?key=" + session->getID() + "&ID=";
+                string baseURL;
+                if (!strncmp(exportLocation.second, "http", 4))
+                    baseURL = exportLocation.second;
+                else
+                    baseURL = string(request.getHandlerURL(targetURL.c_str())) + exportLocation.second;
+                baseURL = baseURL + "?key=" + session->getID() + "&ID=";
                 const vector<const char*>& tokens = session->getAssertionIDs();
                 vector<const char*>::size_type count = 0;
                 for (vector<const char*>::const_iterator tokenids = tokens.begin(); tokenids!=tokens.end(); ++tokenids) {
@@ -375,8 +394,8 @@ pair<bool,long> ServiceProvider::doExport(SPRequest& request, bool requireSessio
 
         // Export the attributes.
         bool remoteUserSet = false;
-        const multimap<string,Attribute*>& attributes = session->getAttributes();
-        for (multimap<string,Attribute*>::const_iterator a = attributes.begin(); a!=attributes.end(); ++a) {
+        const multimap<string,const Attribute*>& attributes = session->getIndexedAttributes();
+        for (multimap<string,const Attribute*>::const_iterator a = attributes.begin(); a!=attributes.end(); ++a) {
             const vector<string>& vals = a->second->getSerializedValues();
 
             // See if this needs to be set as the REMOTE_USER value.