#include "SPRequest.h"
#include "handler/AbstractHandler.h"
#include "remoting/ListenerService.h"
+#include "util/SPConstants.h"
+
+#ifndef SHIBSP_LITE
+# include <saml/SAMLConfig.h>
+# include <saml/binding/SAMLArtifact.h>
+# include <saml/saml1/core/Protocols.h>
+# include <saml/saml2/core/Protocols.h>
+# include <saml/util/SAMLConstants.h>
+# include <xmltooling/util/StorageService.h>
+#else
+# include "lite/SAMLConstants.h"
+#endif
-#include <log4cpp/Category.hh>
-#include <saml/saml1/core/Protocols.h>
-#include <saml/saml2/core/Protocols.h>
-#include <saml/util/SAMLConstants.h>
#include <xmltooling/XMLToolingConfig.h>
-#include <xmltooling/util/StorageService.h>
#include <xmltooling/util/URLEncoder.h>
using namespace shibsp;
using namespace std;
namespace shibsp {
- SHIBSP_DLLLOCAL PluginManager<Handler,pair<const DOMElement*,const char*>>::Factory SAML1ConsumerFactory;
- SHIBSP_DLLLOCAL PluginManager<Handler,pair<const DOMElement*,const char*>>::Factory SAML2ConsumerFactory;
- SHIBSP_DLLLOCAL PluginManager<Handler,pair<const DOMElement*,const char*>>::Factory ChainingSessionInitiatorFactory;
- SHIBSP_DLLLOCAL PluginManager<Handler,pair<const DOMElement*,const char*>>::Factory Shib1SessionInitiatorFactory;
+ SHIBSP_DLLLOCAL PluginManager<Handler,string,pair<const DOMElement*,const char*>>::Factory SAML1ConsumerFactory;
+ SHIBSP_DLLLOCAL PluginManager<Handler,string,pair<const DOMElement*,const char*>>::Factory SAML2ConsumerFactory;
+ SHIBSP_DLLLOCAL PluginManager<Handler,string,pair<const DOMElement*,const char*>>::Factory SAML2ArtifactResolutionFactory;
};
void SHIBSP_API shibsp::registerHandlers()
conf.AssertionConsumerServiceManager.registerFactory(SAML20_BINDING_HTTP_POST, SAML2ConsumerFactory);
conf.AssertionConsumerServiceManager.registerFactory(SAML20_BINDING_HTTP_POST_SIMPLESIGN, SAML2ConsumerFactory);
- conf.SessionInitiatorManager.registerFactory(CHAINING_SESSION_INITIATOR, ChainingSessionInitiatorFactory);
- conf.SessionInitiatorManager.registerFactory(SHIB1_SESSION_INITIATOR, Shib1SessionInitiatorFactory);
+ conf.ArtifactResolutionServiceManager.registerFactory(SAML20_BINDING_SOAP, SAML2ArtifactResolutionFactory);
}
AbstractHandler::AbstractHandler(
const DOMElement* e, log4cpp::Category& log, DOMNodeFilter* filter, const map<string,string>* remapper
- ) : m_log(log) {
+ ) : m_log(log), m_configNS(shibspconstants::SHIB2SPCONFIG_NS) {
load(e,log,filter,remapper);
}
+#ifndef SHIBSP_LITE
void AbstractHandler::checkError(const XMLObject* response) const
{
const saml2p::StatusResponseType* r2 = dynamic_cast<const saml2p::StatusResponseType*>(response);
}
}
-void AbstractHandler::preserveRelayState(SPRequest& request, string& relayState) const
+void AbstractHandler::prepareResponse(saml2p::StatusResponseType& response, const XMLCh* code, const XMLCh* subcode, const char* msg) const
{
- pair<bool,const char*> mech=getString("relayState");
- const URLEncoder* urlenc = XMLToolingConfig::getConfig().getURLEncoder();
+ saml2p::Status* status = saml2p::StatusBuilder::buildStatus();
+ saml2p::StatusCode* scode = saml2p::StatusCodeBuilder::buildStatusCode();
+ status->setStatusCode(scode);
+ scode->setValue(code);
+ if (subcode) {
+ saml2p::StatusCode* ssubcode = saml2p::StatusCodeBuilder::buildStatusCode();
+ scode->setStatusCode(ssubcode);
+ ssubcode->setValue(subcode);
+ }
+ if (msg) {
+ pair<bool,bool> flag = getBool("detailedErrors", m_configNS.get());
+ auto_ptr_XMLCh widemsg((flag.first && flag.second) ? msg : "Error processing request.");
+ saml2p::StatusMessage* sm = saml2p::StatusMessageBuilder::buildStatusMessage();
+ status->setStatusMessage(sm);
+ sm->setMessage(widemsg.get());
+ }
+ response.setStatus(status);
+}
+#endif
+
+void AbstractHandler::preserveRelayState(const Application& application, HTTPResponse& response, string& relayState) const
+{
+ if (relayState.empty())
+ return;
// No setting means just pass it by value.
- if (!mech.first || !mech.second || !*mech.second) {
- relayState = urlenc->encode(relayState.c_str());
- }
- else if (!strcmp(mech.second, "cookie")) {
+ pair<bool,const char*> mech=getString("relayState");
+ if (!mech.first || !mech.second || !*mech.second)
+ return;
+
+ if (!strcmp(mech.second, "cookie")) {
// Here we store the state in a cookie and send a fixed
// value so we can recognize it on the way back.
- pair<string,const char*> shib_cookie=request.getApplication().getCookieNameProps("_shibstate_");
- string stateval = urlenc->encode(relayState.c_str()) + shib_cookie.second;
- request.setCookie(shib_cookie.first.c_str(),stateval.c_str());
- relayState = "cookie";
+ if (relayState != "cookie") {
+ const URLEncoder* urlenc = XMLToolingConfig::getConfig().getURLEncoder();
+ pair<string,const char*> shib_cookie=application.getCookieNameProps("_shibstate_");
+ string stateval = urlenc->encode(relayState.c_str()) + shib_cookie.second;
+ response.setCookie(shib_cookie.first.c_str(),stateval.c_str());
+ relayState = "cookie";
+ }
}
else if (strstr(mech.second,"ss:")==mech.second) {
- mech.second+=3;
- if (*mech.second) {
- DDF out,in = DDF("set::RelayState").structure();
- in.addmember("id").string(mech.second);
- in.addmember("value").string(relayState.c_str());
- DDFJanitor jin(in),jout(out);
- out = request.getServiceProvider().getListenerService()->send(in);
- if (!out.isstring())
- throw IOException("StorageService-backed RelayState mechanism did not return a state key.");
- relayState = string(mech.second-3) + ':' + urlenc->encode(out.string());
+ if (relayState.find("ss:")!=0) {
+ mech.second+=3;
+ if (*mech.second) {
+ if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) {
+#ifndef SHIBSP_LITE
+ StorageService* storage = application.getServiceProvider().getStorageService(mech.second);
+ if (storage) {
+ string rsKey;
+ SAMLConfig::getConfig().generateRandomBytes(rsKey,10);
+ rsKey = SAMLArtifact::toHex(rsKey);
+ storage->createString("RelayState", rsKey.c_str(), relayState.c_str(), time(NULL) + 600);
+ relayState = string(mech.second-3) + ':' + rsKey;
+ }
+ else {
+ m_log.error("Storage-backed RelayState with invalid StorageService ID (%s)", mech.second);
+ relayState.erase();
+ }
+#endif
+ }
+ 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());
+ DDFJanitor jin(in),jout(out);
+ out = application.getServiceProvider().getListenerService()->send(in);
+ if (!out.isstring())
+ throw IOException("StorageService-backed RelayState mechanism did not return a state key.");
+ relayState = string(mech.second-3) + ':' + out.string();
+ }
+ }
}
}
else
throw ConfigurationException("Unsupported relayState mechanism ($1).", params(1,mech.second));
}
-void AbstractHandler::recoverRelayState(HTTPRequest& httpRequest, string& relayState) const
+void AbstractHandler::recoverRelayState(const Application& application, HTTPRequest& httpRequest, string& relayState, bool clear) const
{
SPConfig& conf = SPConfig::getConfig();
key++;
if (!ssid.empty() && *key) {
if (conf.isEnabled(SPConfig::OutOfProcess)) {
+#ifndef SHIBSP_LITE
StorageService* storage = conf.getServiceProvider()->getStorageService(ssid.c_str());
if (storage) {
- if (storage->readString("RelayState",key,&relayState)>0)
- storage->deleteString("RelayState",key);
+ ssid = key;
+ if (storage->readString("RelayState",ssid.c_str(),&relayState)>0) {
+ if (clear)
+ storage->deleteString("RelayState",ssid.c_str());
+ return;
+ }
else
- relayState = "default";
+ relayState.erase();
}
else {
Category::getInstance(SHIBSP_LOGCAT".Handler").error(
"Storage-backed RelayState with invalid StorageService ID (%s)", ssid.c_str()
);
- relayState = "default";
+ relayState.erase();
}
+#endif
}
else if (conf.isEnabled(SPConfig::InProcess)) {
- // In process, we should be able to cast down to a full SPRequest.
- SPRequest& request = dynamic_cast<SPRequest&>(httpRequest);
DDF out,in = DDF("get::RelayState").structure();
in.addmember("id").string(ssid.c_str());
in.addmember("key").string(key);
+ in.addmember("clear").integer(clear ? 1 : 0);
DDFJanitor jin(in),jout(out);
- out = request.getServiceProvider().getListenerService()->send(in);
- if (!out.isstring())
- throw IOException("StorageService-backed RelayState mechanism did not return a state value.");
- relayState = out.string();
+ out = application.getServiceProvider().getListenerService()->send(in);
+ if (!out.isstring()) {
+ m_log.error("StorageService-backed RelayState mechanism did not return a state value.");
+ relayState.erase();
+ }
+ else {
+ relayState = out.string();
+ return;
+ }
}
}
}
}
- else if (conf.isEnabled(SPConfig::InProcess)) {
- // In process, we should be able to cast down to a full SPRequest.
- SPRequest& request = dynamic_cast<SPRequest&>(httpRequest);
- if (relayState.empty() || relayState == "cookie") {
+
+ if (conf.isEnabled(SPConfig::InProcess)) {
+ if (relayState == "cookie") {
// Pull the value from the "relay state" cookie.
- pair<string,const char*> relay_cookie = request.getApplication().getCookieNameProps("_shibstate_");
+ pair<string,const char*> relay_cookie = application.getCookieNameProps("_shibstate_");
+ // In process, we should be able to cast down to a full SPRequest.
+ SPRequest& request = dynamic_cast<SPRequest&>(httpRequest);
const char* state = request.getCookie(relay_cookie.first.c_str());
if (state && *state) {
// URL-decode the value.
relayState = rscopy;
free(rscopy);
- // Clear the cookie.
- request.setCookie(relay_cookie.first.c_str(),relay_cookie.second);
+ if (clear)
+ request.setCookie(relay_cookie.first.c_str(),relay_cookie.second);
+ return;
}
- else
- relayState = "default"; // fall through...
+
+ relayState.erase();
}
-
+
// Check for "default" value.
- if (relayState == "default") {
- pair<bool,const char*> homeURL=request.getApplication().getString("homeURL");
+ if (relayState.empty() || relayState == "default") {
+ pair<bool,const char*> homeURL=application.getString("homeURL");
relayState=homeURL.first ? homeURL.second : "/";
+ return;
}
}
+
+ if (relayState == "default")
+ relayState.empty();
}