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.");
+ return sendLogoutPage(application, httpRequest, httpResponse, "partial");
}
#ifndef SHIBSP_LITE
).getByBinding(m_binding.get());
if (!ep) {
throw MetadataException(
- "Unable to locate ADFS single logout service for identity provider ($entityID).", namedparams(1, "entityID", session->getEntityID())
+ "Unable to locate ADFS single logout service for identity provider ($entityID).",
+ namedparams(1, "entityID", session->getEntityID())
);
}
if (param)
return make_pair(true, request.sendRedirect(param));
- return sendLogoutPage(app, request, request, false, "Logout complete.");
+ return sendLogoutPage(app, request, request, "global");
}
postTemplate.html \
localLogout.html \
globalLogout.html \
+ partialLogout.html \
sslError.html
#
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" type="text/css" href="<shibmlp styleSheet/>" />
<title>Global Logout</title>
</head>
<p><strong>Status of Global Logout:</strong> <shibmlp logoutStatus/></p>
-<shibmlpif statusCode>
- <p>Error from your identity provider:</p>
- <blockquote>
- <strong>Status:</strong> <shibmlp statusCode/><br>
- <shibmlpif statusCode2>
- <strong>Sub-Status:</strong> <shibmlp statusCode2/><br>
- </shibmlpif>
- <shibmlpif statusMessage>
- <strong>Message:</strong> <shibmlp statusMessage/><br>
- </shibmlpif>
- </blockquote>
-</shibmlpif>
-
<p>If the message above indicates success, you have been logged out of all
the applications and systems that support the logout mechanism.</p>
-<p>It is still strongly advised that you close your browser to complete the
-logout process.</p>
+<p>Regardless of the outcome, it is strongly advised that you close your browser
+to ensure that you complete the logout process.</p>
</body>
</html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" type="text/css" href="<shibmlp styleSheet/>" />
<title>Local Logout</title>
</head>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" type="text/css" href="<shibmlp styleSheet/>" />
<title>Unknown Identity Provider</title>
</head>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+ <link rel="stylesheet" type="text/css" href="<shibmlp styleSheet/>" />
+ <title>Partial Logout</title>
+</head>
+
+<body>
+
+<img src="<shibmlp logoLocation/>" alt="Logo" />
+<h1>Partial Logout</h1>
+
+<p>You remain logged into one or more applications accessed during your session.
+To complete the logout process, please close/exit your browser completely.</p>
+
+</body>
+</html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" type="text/css" href="<shibmlp styleSheet/>" />
<title><shibmlp errorType/></title>
</head>
<blockquote>
<strong>Status:</strong> <shibmlp statusCode/><br>
<shibmlpif statusCode2>
- <strong>Sub-Status:</strong> <shibmlp statusCode2/><br>
+ <strong>Sub-Status:</strong> <shibmlp statusCode2/><br/>
</shibmlpif>
<shibmlpif statusMessage>
- <strong>Message:</strong> <shibmlp statusMessage/><br>
+ <strong>Message:</strong> <shibmlp statusMessage/><br/>
</shibmlpif>
</blockquote>
</shibmlpif>
metadata="metadataError.html"
access="accessError.html"
ssl="sslError.html"
- localLogout="localLogout.html"
- globalLogout="globalLogout.html"
supportContact="root@localhost"
logoLocation="/shibboleth-sp/logo.jpg"
styleSheet="/shibboleth-sp/main.css"/>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" type="text/css" href="<shibmlp styleSheet/>" />
<title>POST Failed</title>
</head>
<img src="<shibmlp logoLocation/>" alt="Logo" />
<h1>POST Failed</h1>
-
+<p>
You have attemped to submit information without the protection
-of SSL to this site.<br>
+of SSL to this site.<br/>
+</p>
+<p>
For the protection of your submission and the integrity of the site,
this is not permitted. Please try accessing the server with a
URL starting with <strong>https://</strong> and report this problem
to <a href="mailto:<shibmlp supportContact/>"><shibmlp supportContact/></a>
+</p>
</body>
</html>
FileSystemObj.CopyFile DistDir & "globalLogout.html", ConfigDir, false
End If
+ If (NOT FileSystemObj.FileExists(ConfigDir & "partialLogout.html")) then
+ FileSystemObj.CopyFile DistDir & "partialLogout.html", ConfigDir, false
+ End If
+
If (NOT FileSystemObj.FileExists(ConfigDir & "console.logger")) then
FileSystemObj.CopyFile DistDir & "console.logger", ConfigDir, false
End If
<attribute name="ssl" type="anyURI"/>\r
<attribute name="localLogout" type="anyURI"/>\r
<attribute name="globalLogout" type="anyURI"/>\r
+ <attribute name="partialLogout" type="anyURI"/>\r
<attribute name="supportContact" type="conf:string"/>\r
<attribute name="logoLocation" type="anyURI"/>\r
<attribute name="styleSheet" type="anyURI"/>\r
) const;
/**
+ * @deprecated
* Sends a response template to the user agent informing it of the results of a logout attempt.
*
* @param application the Application to use in determining the logout template
bool local=true,
const char* status=NULL
) const;
+
+ /**
+ * Sends a response template to the user agent informing it of the results of a logout attempt.
+ *
+ * @param application the Application to use in determining the logout template
+ * @param request the HTTP client request to supply to the template
+ * @param response the HTTP response to use
+ * @param type designates the prefix of logout template name to use
+ */
+ std::pair<bool,long> sendLogoutPage(
+ const Application& application,
+ const xmltooling::HTTPRequest& request,
+ xmltooling::HTTPResponse& response,
+ const char* type
+ ) const;
};
#if defined (_MSC_VER)
if (!session_id.empty()) {
// Do back channel notification.
vector<string> sessions(1, session_id);
- if (!notifyBackChannel(app, request.getRequestURL(), sessions, true)) {
- app.getServiceProvider().getSessionCache()->remove(app, request, &request);
- return sendLogoutPage(app, request, request, true, "Partial logout failure.");
- }
- request.getServiceProvider().getSessionCache()->remove(app, request, &request);
+ bool result = notifyBackChannel(app, request.getRequestURL(), sessions, true);
+ app.getServiceProvider().getSessionCache()->remove(app, request, &request);
+ if (!result)
+ return sendLogoutPage(app, request, request, "partial");
}
// 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.");
+ return sendLogoutPage(app, request, request, "local");
}
const Application& application, const HTTPRequest& request, HTTPResponse& response, bool local, const char* status
) const
{
+ return sendLogoutPage(application, request, response, local ? "local" : "global");
+}
+
+pair<bool,long> LogoutHandler::sendLogoutPage(
+ const Application& application, const HTTPRequest& request, HTTPResponse& response, const char* type
+ ) const
+{
+ string tname = string(type) + "Logout";
const PropertySet* props = application.getPropertySet("Errors");
- pair<bool,const char*> prop = props ? props->getString(local ? "localLogout" : "globalLogout") : pair<bool,const char*>(false,NULL);
- if (prop.first) {
- response.setContentType("text/html");
- response.setResponseHeader("Expires","01-Jan-1997 12:00:00 GMT");
- response.setResponseHeader("Cache-Control","private,no-store,no-cache");
- string fname(prop.second);
- ifstream infile(XMLToolingConfig::getConfig().getPathResolver()->resolve(fname, PathResolver::XMLTOOLING_CFG_FILE).c_str());
- if (!infile)
- throw ConfigurationException("Unable to access $1 HTML template.", params(1,local ? "localLogout" : "globalLogout"));
- TemplateParameters tp;
- tp.m_request = &request;
- tp.setPropertySet(props);
- if (status)
- tp.m_map["logoutStatus"] = status;
- stringstream str;
- XMLToolingConfig::getConfig().getTemplateEngine()->run(infile, str, tp);
- return make_pair(true,response.sendResponse(str));
- }
- prop = application.getString("homeURL");
- if (prop.first)
- return make_pair(true,response.sendRedirect(prop.second));
-
- // No homeURL, so compute a URL to the root of the site.
- int port = request.getPort();
- const char* scheme = request.getScheme();
- string dest = string(scheme) + "://" + request.getHostname();
- if ((!strcmp(scheme,"http") && port!=80) || (!strcmp(scheme,"https") && port!=443)) {
- ostringstream portstr;
- portstr << port;
- dest += ":" + portstr.str();
- }
- dest += '/';
- return make_pair(true,response.sendRedirect(dest.c_str()));
+ pair<bool,const char*> prop = props ? props->getString(tname.c_str()) : pair<bool,const char*>(false,NULL);
+ if (!prop.first)
+ prop.second = tname.c_str();
+ response.setContentType("text/html");
+ response.setResponseHeader("Expires","01-Jan-1997 12:00:00 GMT");
+ response.setResponseHeader("Cache-Control","private,no-store,no-cache");
+ string fname(prop.second);
+ ifstream infile(XMLToolingConfig::getConfig().getPathResolver()->resolve(fname, PathResolver::XMLTOOLING_CFG_FILE).c_str());
+ if (!infile)
+ throw ConfigurationException("Unable to access $1 HTML template.", params(1,prop.second));
+ TemplateParameters tp;
+ tp.m_request = &request;
+ tp.setPropertySet(props);
+ tp.m_map["logoutStatus"] = "Logout completed successfully."; // Backward compatibility.
+ stringstream str;
+ XMLToolingConfig::getConfig().getTemplateEngine()->run(infile, str, tp);
+ return make_pair(true,response.sendResponse(str));
}
pair<bool,long> LogoutHandler::run(SPRequest& request, bool isHandler) const
// If relay state is set, recover the original return URL.
if (!relayState.empty())
recoverRelayState(application, request, response, relayState);
+
+ // Check for partial logout.
+ const StatusCode* sc = logoutResponse->getStatus() ? logoutResponse->getStatus()->getStatusCode() : NULL;
+ sc = sc ? sc->getStatusCode() : NULL;
+ if (sc && XMLString::equals(sc->getValue(), StatusCode::PARTIAL_LOGOUT))
+ return sendLogoutPage(application, request, response, "partial");
+
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.");
+ // Return template for completion of logout.
+ return sendLogoutPage(application, request, response, "global");
}
FatalProfileException ex("Incoming message was not a samlp:LogoutRequest or samlp:LogoutResponse.");
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.");
+ return sendLogoutPage(application, httpRequest, httpResponse, "partial");
}
#ifndef SHIBSP_LITE
}
}
if (!ep || !encoder) {
- m_log.warn("no compatible front channel SingleLogoutService, trying back channel...");
+ m_log.debug("no compatible front channel SingleLogoutService, trying back channel...");
shibsp::SecurityPolicy policy(application);
shibsp::SOAPClient soaper(policy);
MetadataCredentialCriteria mcc(*role);
}
}
+ // No answer at all?
if (!logoutResponse) {
- ret = sendLogoutPage(
- application, httpRequest, httpResponse, false,
- endpoints.empty() ?
- "Identity provider does not support SAML 2 Single Logout protocol." :
- "Identity provider did not respond to logout request."
- );
+ if (endpoints.empty())
+ m_log.info("IdP doesn't support single logout protocol over a compatible binding");
+ else
+ m_log.warn("IdP didn't respond to logout request");
+ ret = sendLogoutPage(application, httpRequest, httpResponse, "partial");
}
- else if (!logoutResponse->getStatus() || !logoutResponse->getStatus()->getStatusCode() ||
- !XMLString::equals(logoutResponse->getStatus()->getStatusCode()->getValue(), saml2p::StatusCode::SUCCESS)) {
- delete logoutResponse;
- ret = sendLogoutPage(application, httpRequest, httpResponse, false, "Identity provider returned a SAML error in response to logout request.");
+
+ // Check the status, looking for non-success or a partial logout code.
+ const StatusCode* sc = logoutResponse->getStatus() ? logoutResponse->getStatus()->getStatusCode() : NULL;
+ bool partial = (!sc || !XMLString::equals(sc->getValue(), StatusCode::SUCCESS));
+ if (!partial) {
+ // Success, but still need to check for partial.
+ partial = XMLString::equals(sc->getStatusCode()->getValue(), StatusCode::PARTIAL_LOGOUT);
}
+ delete logoutResponse;
+ if (partial)
+ ret = sendLogoutPage(application, httpRequest, httpResponse, "partial");
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.");
+ ret = sendLogoutPage(application, httpRequest, httpResponse, "global");
}
if (session) {