https://issues.shibboleth.net/jira/browse/SSPCPP-255
[shibboleth/cpp-sp.git] / shibsp / handler / impl / AbstractHandler.cpp
index 510b6ff..d1c8d58 100644 (file)
@@ -21,8 +21,8 @@
  */
 
 #include "internal.h"
-#include "Application.h"
 #include "exceptions.h"
+#include "Application.h"
 #include "ServiceProvider.h"
 #include "SPRequest.h"
 #include "handler/AbstractHandler.h"
 
 
 #ifndef SHIBSP_LITE
+# include <saml/exceptions.h>
+# include <saml/SAMLConfig.h>
+# include <saml/binding/SAMLArtifact.h>
 # include <saml/saml1/core/Protocols.h>
 # include <saml/saml2/core/Protocols.h>
 # include <saml/saml2/metadata/Metadata.h>
 # include <saml/saml2/metadata/MetadataCredentialCriteria.h>
 # include <saml/util/SAMLConstants.h>
-# include <saml/SAMLConfig.h>
-# include <saml/binding/SAMLArtifact.h>
+# include <xmltooling/security/Credential.h>
+# include <xmltooling/security/CredentialResolver.h>
 # include <xmltooling/util/StorageService.h>
 using namespace opensaml::saml2md;
+using namespace opensaml;
 #else
 # include "lite/SAMLConstants.h"
 #endif
@@ -58,7 +62,6 @@ using namespace opensaml::saml2md;
 
 using namespace shibsp;
 using namespace samlconstants;
-using namespace opensaml;
 using namespace xmltooling;
 using namespace xercesc;
 using namespace std;
@@ -128,14 +131,31 @@ void SHIBSP_API shibsp::registerHandlers()
     conf.ManageNameIDServiceManager.registerFactory(SAML20_BINDING_HTTP_ARTIFACT, SAML2NameIDMgmtFactory);
 }
 
+Handler::Handler()
+{
+}
+
+Handler::~Handler()
+{
+}
+
 AbstractHandler::AbstractHandler(
     const DOMElement* e, Category& log, DOMNodeFilter* filter, const map<string,string>* remapper
     ) : m_log(log), m_configNS(shibspconstants::SHIB2SPCONFIG_NS) {
     load(e,NULL,filter,remapper);
 }
 
+AbstractHandler::~AbstractHandler()
+{
+}
+
 #ifndef SHIBSP_LITE
 
+const char* Handler::getType() const
+{
+    return getString("type").second;
+}
+
 void AbstractHandler::checkError(const XMLObject* response, const saml2md::RoleDescriptor* role) const
 {
     const saml2p::StatusResponseType* r2 = dynamic_cast<const saml2p::StatusResponseType*>(response);
@@ -316,7 +336,7 @@ void AbstractHandler::preserveRelayState(const Application& application, HTTPRes
                 else if (SPConfig::getConfig().isEnabled(SPConfig::InProcess)) {
                     DDF out,in = DDF("set::RelayState").structure();
                     in.addmember("id").string(mech.second);
-                    in.addmember("value").string(relayState.c_str());
+                    in.addmember("value").unsafe_string(relayState.c_str());
                     DDFJanitor jin(in),jout(out);
                     out = application.getServiceProvider().getListenerService()->send(in);
                     if (!out.isstring())
@@ -414,7 +434,20 @@ void AbstractHandler::recoverRelayState(
     // Check for "default" value (or the old "cookie" value that might come from stale bookmarks).
     if (relayState.empty() || relayState == "default" || relayState == "cookie") {
         pair<bool,const char*> homeURL=application.getString("homeURL");
-        relayState=homeURL.first ? homeURL.second : "/";
+        if (homeURL.first)
+            relayState=homeURL.second;
+        else {
+            // Compute a URL to the root of the site.
+            int port = request.getPort();
+            const char* scheme = request.getScheme();
+            relayState = string(scheme) + "://" + request.getHostname();
+            if ((!strcmp(scheme,"http") && port!=80) || (!strcmp(scheme,"https") && port!=443)) {
+                ostringstream portstr;
+                portstr << port;
+                relayState += ":" + portstr.str();
+            }
+            relayState += '/';
+        }
     }
 }
 
@@ -422,8 +455,11 @@ void AbstractHandler::preservePostData(
     const Application& application, const HTTPRequest& request, HTTPResponse& response, const char* relayState
     ) const
 {
-    if (strcmp(request.getMethod(), "POST"))
-        return;
+#ifdef HAVE_STRCASECMP
+    if (strcasecmp(request.getMethod(), "POST")) return;
+#else
+    if (stricmp(request.getMethod(), "POST")) return;
+#endif
 
     // No specs mean no save.
     const PropertySet* props=application.getPropertySet("Sessions");
@@ -553,6 +589,8 @@ long AbstractHandler::sendPostResponse(
     const Application& application, HTTPResponse& httpResponse, const char* url, DDF& postData
     ) const
 {
+    HTTPResponse::sanitizeURL(url);
+
     const PropertySet* props=application.getPropertySet("Sessions");
     pair<bool,const char*> postTemplate = props->getString("postTemplate");
     if (!postTemplate.first)
@@ -568,18 +606,22 @@ long AbstractHandler::sendPostResponse(
     // Load the parameters into objects for the template.
     multimap<string,string>& collection = respParam.m_collectionMap["PostedData"];
     DDF param = postData.first();
-    while (param.isstring()) {
-        collection.insert(pair<string,string>(param.name(), (param.string() ? param.string() : "")));
+    while (!param.isnull()) {
+        collection.insert(pair<const string,string>(param.name(), (param.string() ? param.string() : "")));
         param = postData.next();
     }
 
     stringstream str;
     XMLToolingConfig::getConfig().getTemplateEngine()->run(infile, str, respParam);
 
+    pair<bool,bool> postExpire = props->getBool("postExpire");
+
     httpResponse.setContentType("text/html");
-    httpResponse.setResponseHeader("Expires", "01-Jan-1997 12:00:00 GMT");
-    httpResponse.setResponseHeader("Cache-Control", "no-cache, no-store, must-revalidate, private");
-    httpResponse.setResponseHeader("Pragma", "no-cache");
+    if (!postExpire.first || postExpire.second) {
+        httpResponse.setResponseHeader("Expires", "01-Jan-1997 12:00:00 GMT");
+        httpResponse.setResponseHeader("Cache-Control", "no-cache, no-store, must-revalidate, private");
+        httpResponse.setResponseHeader("Pragma", "no-cache");
+    }
     return httpResponse.sendResponse(str);
 }
 
@@ -612,12 +654,12 @@ DDF AbstractHandler::getPostData(const Application& application, const HTTPReque
             CGIParser cgi(request);
             pair<CGIParser::walker,CGIParser::walker> params = cgi.getParameters(NULL);
             if (params.first == params.second)
-                return DDF();
+                return DDF("parameters").list();
             DDF child;
             DDF ret = DDF("parameters").list();
             for (; params.first != params.second; ++params.first) {
                 if (!params.first->first.empty()) {
-                    child = DDF(params.first->first.c_str()).string(params.first->second);
+                    child = DDF(params.first->first.c_str()).unsafe_string(params.first->second);
                     ret.add(child);
                 }
             }
@@ -630,5 +672,5 @@ DDF AbstractHandler::getPostData(const Application& application, const HTTPReque
     else {
         m_log.info("ignoring POST data with non-standard encoding (%s)", contentType.c_str());
     }
-    return NULL;
+    return DDF();
 }