#endif
};
- class SHIBSP_DLLLOCAL ADFSLogoutInitiator : public AbstractHandler, public RemotedHandler
+ class SHIBSP_DLLLOCAL ADFSLogoutInitiator : public AbstractHandler, public LogoutHandler
{
public:
ADFSLogoutInitiator(const DOMElement* e, const char* appId)
#endif
private:
- pair<bool,long> doRequest(const Application& application, const char* entityID, HTTPResponse& httpResponse) const;
+ pair<bool,long> doRequest(const Application& application, const HTTPRequest& httpRequest, HTTPResponse& httpResponse, Session* session) const;
string m_appId;
auto_ptr_XMLCh m_binding;
if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) {
// When out of process, we run natively.
- return doRequest(request.getApplication(), entityID.c_str(), request);
+ return doRequest(request.getApplication(), request, request, session);
}
else {
// When not out of process, we remote the request.
- Locker locker(session, false);
- DDF out,in(m_address.c_str());
+ session->unlock();
+ vector<string> headers(1,"Cookie");
+ DDF out,in = wrap(request,&headers);
DDFJanitor jin(in), jout(out);
- in.addmember("application_id").string(request.getApplication().getId());
- in.addmember("entity_id").string(entityID.c_str());
out=request.getServiceProvider().getListenerService()->send(in);
return unwrap(request, out);
}
void ADFSLogoutInitiator::receive(DDF& in, ostream& out)
{
#ifndef SHIBSP_LITE
+ // Defer to base class for notifications
+ if (in["notify"].integer() == 1)
+ return LogoutHandler::receive(in, out);
+
// Find application.
const char* aid=in["application_id"].string();
const Application* app=aid ? SPConfig::getConfig().getServiceProvider()->getApplication(aid) : NULL;
throw ConfigurationException("Unable to locate application for logout, deleted?");
}
+ // Unpack the request.
+ auto_ptr<HTTPRequest> req(getRequest(in));
+
// Set up a response shim.
DDF ret(NULL);
DDFJanitor jout(ret);
auto_ptr<HTTPResponse> resp(getResponse(ret));
- // Since we're remoted, the result should either be a throw, which we pass on,
- // a false/0 return, which we just return as an empty structure, or a response/redirect,
- // which we capture in the facade and send back.
- doRequest(*app, in["entity_id"].string(), *resp.get());
+ Session* session = NULL;
+ try {
+ session = app->getServiceProvider().getSessionCache()->find(*app, *req.get(), NULL, NULL);
+ }
+ catch (exception& ex) {
+ m_log.error("error accessing current session: %s", ex.what());
+ }
+ // With no session, we just skip the request and let it fall through to an empty struct return.
+ if (session) {
+ if (session->getEntityID()) {
+ // Since we're remoted, the result should either be a throw, which we pass on,
+ // a false/0 return, which we just return as an empty structure, or a response/redirect,
+ // which we capture in the facade and send back.
+ doRequest(*app, *req.get(), *resp.get(), session);
+ }
+ else {
+ m_log.error("no issuing entityID found in session");
+ session->unlock();
+ app->getServiceProvider().getSessionCache()->remove(*app, *req.get(), resp.get());
+ }
+ }
out << ret;
#else
throw ConfigurationException("Cannot perform logout using lite version of shibsp library.");
#endif
}
-pair<bool,long> ADFSLogoutInitiator::doRequest(const Application& application, const char* entityID, HTTPResponse& response) const
+pair<bool,long> ADFSLogoutInitiator::doRequest(
+ const Application& application, const HTTPRequest& httpRequest, HTTPResponse& httpResponse, Session* session
+ ) const
{
+ // Do back channel notification.
+ vector<string> sessions(1, session->getID());
+ if (!notifyBackChannel(application, httpRequest.getRequestURL(), sessions, false)) {
+ session->unlock();
+ application.getServiceProvider().getSessionCache()->remove(application, httpRequest, &httpResponse);
+ return sendLogoutPage(application, httpRequest, httpResponse, true, "Partial logout failure.");
+ }
+
#ifndef SHIBSP_LITE
- try {
- if (!entityID)
- throw ConfigurationException("Missing entityID parameter.");
+ pair<bool,long> ret = make_pair(false,0L);
+ try {
// With a session in hand, we can create a request message, if we can find a compatible endpoint.
MetadataProvider* m=application.getMetadataProvider();
- Locker locker(m);
- MetadataProvider::Criteria mc(entityID, &IDPSSODescriptor::ELEMENT_QNAME, m_binding.get());
+ Locker metadataLocker(m);
+ MetadataProvider::Criteria mc(session->getEntityID(), &IDPSSODescriptor::ELEMENT_QNAME, m_binding.get());
pair<const EntityDescriptor*,const RoleDescriptor*> entity=m->getEntityDescriptor(mc);
- if (!entity.first)
- throw MetadataException("Unable to locate metadata for identity provider ($entityID)", namedparams(1, "entityID", entityID));
- else if (!entity.second)
- throw MetadataException("Unable to locate ADFS IdP role for identity provider ($entityID).", namedparams(1, "entityID", entityID));
-
+ if (!entity.first) {
+ throw MetadataException(
+ "Unable to locate metadata for identity provider ($entityID)", namedparams(1, "entityID", session->getEntityID())
+ );
+ }
+ else if (!entity.second) {
+ throw MetadataException(
+ "Unable to locate ADFS IdP role for identity provider ($entityID).", namedparams(1, "entityID", session->getEntityID())
+ );
+ }
+
const EndpointType* ep = EndpointManager<SingleLogoutService>(
dynamic_cast<const IDPSSODescriptor*>(entity.second)->getSingleLogoutServices()
).getByBinding(m_binding.get());
if (!ep) {
throw MetadataException(
- "Unable to locate ADFS single logout service for identity provider ($entityID).",
- namedparams(1, "entityID", entityID)
+ "Unable to locate ADFS single logout service for identity provider ($entityID).", namedparams(1, "entityID", session->getEntityID())
);
}
+ // Save off return location as RelayState.
+ string relayState;
+ const char* returnloc = httpRequest.getParameter("return");
+ if (returnloc) {
+ relayState = returnloc;
+ preserveRelayState(application, httpResponse, relayState);
+ }
+
auto_ptr_char dest(ep->getLocation());
-
string req=string(dest.get()) + (strchr(dest.get(),'?') ? '&' : '?') + "wa=wsignout1.0";
- return make_pair(true,response.sendRedirect(req.c_str()));
+ if (!relayState.empty())
+ req += "&wreply=" + relayState;
+ ret.second = httpResponse.sendRedirect(req.c_str());
+ ret.first = true;
}
catch (exception& ex) {
m_log.error("error issuing ADFS logout request: %s", ex.what());
}
- return make_pair(false,0L);
+ if (session) {
+ session->unlock();
+ session = NULL;
+ application.getServiceProvider().getSessionCache()->remove(application, httpRequest, &httpResponse);
+ }
+
+ return ret;
#else
throw ConfigurationException("Cannot perform logout using lite version of shibsp library.");
#endif