<attribute name="authPassword" type="conf:string"/>\r
<attribute name="signRequests" type="boolean" default="false"/>
<attribute name="signatureAlg" type="anyURI"/>\r
+ <attribute name="digestAlg" type="anyURI"/>\r
<attribute name="encryptRequests" type="boolean" default="true"/>\r
+ <attribute name="encryptionAlg" type="anyURI"/>\r
</attributeGroup>\r
\r
<element name="SecurityPolicies">
* such as cookies or StorageService-backed keys.
*
* <p>If a supported mechanism can be identified, the input parameter will be
- * replaced with a suitable state key, URL-encoded.
+ * replaced with a suitable state key.
*
* @param request the active SPRequest
* @param relayState RelayState token to supply with message
*
* @param httpRequest incoming HTTP request
* @param relayState RelayState token supplied with message
+ * @param clear true iff the token state should be cleared
*/
- virtual void recoverRelayState(opensaml::HTTPRequest& httpRequest, std::string& relayState) const;
+ virtual void recoverRelayState(opensaml::HTTPRequest& httpRequest, std::string& relayState, bool clear=true) const;
/** Logging object. */
log4cpp::Category& m_log;
void AbstractHandler::preserveRelayState(SPRequest& request, string& relayState) const
{
- pair<bool,const char*> mech=getString("relayState");
- const URLEncoder* urlenc = XMLToolingConfig::getConfig().getURLEncoder();
+ 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=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";
+ }
}
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) {
+ 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) + ':' + out.string();
+ }
}
}
else
throw ConfigurationException("Unsupported relayState mechanism ($1).", params(1,mech.second));
}
-void AbstractHandler::recoverRelayState(HTTPRequest& httpRequest, string& relayState) const
+void AbstractHandler::recoverRelayState(HTTPRequest& httpRequest, string& relayState, bool clear) const
{
SPConfig& conf = SPConfig::getConfig();
if (conf.isEnabled(SPConfig::OutOfProcess)) {
StorageService* storage = conf.getServiceProvider()->getStorageService(ssid.c_str());
if (storage) {
- if (storage->readString("RelayState",key,&relayState)>0)
- storage->deleteString("RelayState",key);
+ if (storage->readString("RelayState",key,&relayState)>0) {
+ if (clear)
+ storage->deleteString("RelayState",key);
+ 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();
}
}
else if (conf.isEnabled(SPConfig::InProcess)) {
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();
+ if (!out.isstring()) {
+ Category::getInstance(SHIBSP_LOGCAT".Handler").error(
+ "StorageService-backed RelayState mechanism did not return a state value."
+ );
+ relayState.erase();
+ }
+ else {
+ relayState = out.string();
+ return;
+ }
}
}
}
}
- else if (conf.isEnabled(SPConfig::InProcess)) {
+
+ 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 (relayState == "cookie") {
// Pull the value from the "relay state" cookie.
pair<string,const char*> relay_cookie = request.getApplication().getCookieNameProps("_shibstate_");
const char* state = request.getCookie(relay_cookie.first.c_str());
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") {
+ if (relayState.empty() || relayState == "default") {
pair<bool,const char*> homeURL=request.getApplication().getString("homeURL");
relayState=homeURL.first ? homeURL.second : "/";
+ return;
}
}
+
+ if (relayState == "default")
+ relayState.empty();
}
return make_pair(false,0);
string target;
+ const char* option;
bool isPassive=false;
const Application& app=request.getApplication();
if (isHandler) {
- const char* option = request.getParameter("target");
+ option = request.getParameter("target");
if (option)
target = option;
- recoverRelayState(request, target);
+ recoverRelayState(request, target, false);
option = request.getParameter("isPassive");
if (option)
pair<bool,const char*> thisloc = getString("Location");
if (thisloc.first) returnURL += thisloc.second;
+ if (isHandler) {
+ // We may already have RelayState set if we looped back here,
+ // but just in case target is a resource, we reset it back.
+ option = request.getParameter("target");
+ if (option)
+ target = option;
+ }
preserveRelayState(request, target);
+ const URLEncoder* urlenc = XMLToolingConfig::getConfig().getURLEncoder();
if (isHandler) {
// Now the hard part. The base assumption is to append the entire query string, if any,
// to the self-link. But we want to replace target with the RelayState-preserved value
// Now append the sanitized target as needed.
if (!target.empty())
- returnURL = returnURL + (returnURL.rfind('?')==string::npos ? '?' : '&') + "target=" + target;
+ returnURL = returnURL + (returnURL.rfind('?')==string::npos ? '?' : '&') + "target=" + urlenc->encode(target.c_str());
}
else if (!target.empty()) {
// For a virtual handler, we just append target to the return link.
- returnURL = returnURL + "?target=" + target;
+ returnURL = returnURL + "?target=" + urlenc->encode(target.c_str());;
}
-
- const URLEncoder* urlenc = XMLToolingConfig::getConfig().getURLEncoder();
-
string req=string(m_url) + (strchr(m_url,'?') ? '&' : '?') + "entityID=" + urlenc->encode(app.getString("entityID").second) +
"&return=" + urlenc->encode(returnURL.c_str());
if (m_returnParam)
return make_pair(false,0);
string target;
+ const char* option;
const Handler* ACS=NULL;
const Application& app=request.getApplication();
if (isHandler) {
- const char* option=request.getParameter("acsIndex");
+ option=request.getParameter("acsIndex");
if (option)
ACS=app.getAssertionConsumerServiceByIndex(atoi(option));
option = request.getParameter("target");
if (option)
target = option;
- recoverRelayState(request, target);
+ recoverRelayState(request, target, false);
}
else {
// We're running as a "virtual handler" from within the filter.
pair<bool,const char*> loc=ACS ? ACS->getString("Location") : pair<bool,const char*>(false,NULL);
if (loc.first) ACSloc+=loc.second;
+ if (isHandler) {
+ // We may already have RelayState set if we looped back here,
+ // but just in case target is a resource, we reset it back.
+ option = request.getParameter("target");
+ if (option)
+ target = option;
+ }
preserveRelayState(request, target);
+ // Shib 1.x requires a target value.
+ if (target.empty())
+ target = "default";
+
char timebuf[16];
sprintf(timebuf,"%u",time(NULL));
const URLEncoder* urlenc = XMLToolingConfig::getConfig().getURLEncoder();
- string req=string(dest.get()) + "?shire=" + urlenc->encode(ACSloc.c_str()) + "&time=" + timebuf + "&target=" + target +
+ string req=string(dest.get()) + (strchr(dest.get(),'?') ? '&' : '?') + "shire=" + urlenc->encode(ACSloc.c_str()) +
+ "&time=" + timebuf + "&target=" + urlenc->encode(target.c_str()) +
"&providerId=" + urlenc->encode(app.getString("entityID").second);
return make_pair(true, request.sendRedirect(req.c_str()));
return make_pair(false,0);
string target;
+ const char* option;
const Handler* ACS=NULL;
const Application& app=request.getApplication();
if (isHandler) {
- const char* option=request.getParameter("acsIndex");
+ option=request.getParameter("acsIndex");
if (option)
ACS=app.getAssertionConsumerServiceByIndex(atoi(option));
option = request.getParameter("target");
if (option)
target = option;
- recoverRelayState(request, target);
+ recoverRelayState(request, target, false);
}
else {
// We're running as a "virtual handler" from within the filter.
pair<bool,const char*> loc=ACS ? ACS->getString("Location") : pair<bool,const char*>(false,NULL);
if (loc.first) ACSloc+=loc.second;
+ if (isHandler) {
+ // We may already have RelayState set if we looped back here,
+ // but just in case target is a resource, we reset it back.
+ option = request.getParameter("target");
+ if (option)
+ target = option;
+ }
preserveRelayState(request, target);
+ // WAYF requires a target value.
+ if (target.empty())
+ target = "default";
+
char timebuf[16];
sprintf(timebuf,"%u",time(NULL));
const URLEncoder* urlenc = XMLToolingConfig::getConfig().getURLEncoder();
string req=string(m_url) + (strchr(m_url,'?') ? '&' : '?') + "shire=" + urlenc->encode(ACSloc.c_str()) +
- "&time=" + timebuf + "&target=" + target +
+ "&time=" + timebuf + "&target=" + urlenc->encode(target.c_str()) +
"&providerId=" + urlenc->encode(app.getString("entityID").second);
return make_pair(true, request.sendRedirect(req.c_str()));