Binding="urn:oasis:names:tc:SAML:1.0:profiles:artifact-01"/>
<!-- LogoutInitiators enable SP-initiated local or global/single logout of sessions. -->
- <LogoutInitiator type="Chaining" Location="/Logout">
+ <LogoutInitiator type="Chaining" Location="/Logout" relayState="cookie">
<LogoutInitiator type="SAML2" template="@-PKGSYSCONFDIR-@/bindingTemplate.html"/>
<LogoutInitiator type="Local"/>
</LogoutInitiator>
<any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>\r
</sequence>\r
<attribute name="Location" type="anyURI"/>\r
+ <attribute name="relayState" type="conf:string"/>\r
<attribute name="outgoingBindings" type="conf:listOfURIs"/>\r
<attribute name="template" type="anyURI"/>\r
<attribute name="postArtifact" type="boolean"/>\r
request.getServiceProvider().getSessionCache()->remove(app, request, &request);
}
+ // Route back to return location specified, or use the local template.
+ const char* dest = request.getParameter("return");
+ if (dest)
+ return make_pair(true, request.sendRedirect(dest));
return sendLogoutPage(app, request, request, true, "Logout was successful.");
}
if (param)
index = atoi(param);
+ // "return" is a backwards-compatible "eventual destination" to go back to after logout completes.
+ param = request.getParameter("return");
+
// Fetch the next front notification URL and bump the index for the next round trip.
string loc = application.getNotificationURL(request.getRequestURL(), true, index++);
if (loc.empty())
// Add a signal that we're coming back from notification and the next index.
locstr << "?notifying=1&index=" << index;
+ // Add return if set.
+ if (param)
+ locstr << "&return=" << encoder->encode(param);
+
// We preserve anything we're instructed to directly.
if (params) {
for (map<string,string>::const_iterator p = params->begin(); p!=params->end(); ++p)
}
}
- // Add the return parameter to the destination location and redirect.
+ // Add the notifier's return parameter to the destination location and redirect.
+ // This is NOT the same as the return parameter that might be embedded inside it ;-)
loc = loc + "&return=" + encoder->encode(locstr.str().c_str());
return make_pair(true,response.sendRedirect(loc.c_str()));
}
}
checkError(logoutResponse, policy.getIssuerMetadata()); // throws if Status doesn't look good...
+ // If relay state is set, recover the original return URL.
+ if (!relayState.empty())
+ recoverRelayState(application, request, response, relayState);
+ if (!relayState.empty())
+ return make_pair(true, response.sendRedirect(relayState.c_str()));
+
// Return template for completion of global logout, or redirect to homeURL.
return sendLogoutPage(application, request, response, false, "Global logout completed.");
}
}
else {
delete logoutResponse;
+ const char* returnloc = httpRequest.getParameter("return");
+ if (returnloc) {
+ ret.second = httpResponse.sendRedirect(returnloc);
+ ret.first = true;
+ }
ret = sendLogoutPage(application, httpRequest, httpResponse, false, "Logout completed successfully.");
}
return ret;
}
+ // Save off return location as RelayState.
+ string relayState;
+ const char* returnloc = httpRequest.getParameter("return");
+ if (returnloc) {
+ relayState = returnloc;
+ preserveRelayState(application, httpResponse, relayState);
+ }
+
auto_ptr<LogoutRequest> msg(buildRequest(application, *session, *role, encoder));
msg->setDestination(ep->getLocation());
auto_ptr_char dest(ep->getLocation());
- ret.second = sendMessage(*encoder, msg.get(), NULL, dest.get(), role, application, httpResponse);
+ ret.second = sendMessage(*encoder, msg.get(), relayState.c_str(), dest.get(), role, application, httpResponse);
ret.first = true;
msg.release(); // freed by encoder
}