https://issues.shibboleth.net/jira/browse/SSPCPP-236
authorScott Cantor <cantor.2@osu.edu>
Thu, 29 Oct 2009 03:33:49 +0000 (03:33 +0000)
committerScott Cantor <cantor.2@osu.edu>
Thu, 29 Oct 2009 03:33:49 +0000 (03:33 +0000)
16 files changed:
adfs/adfs.cpp
configs/Makefile.am
configs/globalLogout.html
configs/localLogout.html
configs/metadataError.html
configs/partialLogout.html [new file with mode: 0644]
configs/sessionError.html
configs/shibboleth2.xml
configs/sslError.html
msi/scripts/shib_edit_config_files.vbs
schemas/shibboleth-2.0-native-sp-config.xsd
shibsp/handler/LogoutHandler.h
shibsp/handler/impl/LocalLogoutInitiator.cpp
shibsp/handler/impl/LogoutHandler.cpp
shibsp/handler/impl/SAML2Logout.cpp
shibsp/handler/impl/SAML2LogoutInitiator.cpp

index 858227e..41c78e6 100644 (file)
@@ -880,7 +880,7 @@ pair<bool,long> ADFSLogoutInitiator::doRequest(
     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
@@ -908,7 +908,8 @@ pair<bool,long> ADFSLogoutInitiator::doRequest(
             ).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())
                 );
         }
 
@@ -987,5 +988,5 @@ pair<bool,long> ADFSLogout::run(SPRequest& request, bool isHandler) const
 
     if (param)
         return make_pair(true, request.sendRedirect(param));
-    return sendLogoutPage(app, request, request, false, "Logout complete.");
+    return sendLogoutPage(app, request, request, "global");
 }
index 6d3068a..4e83e94 100644 (file)
@@ -46,6 +46,7 @@ CONFIGFILES = \
     postTemplate.html \
        localLogout.html \
        globalLogout.html \
+       partialLogout.html \
        sslError.html
 
 #
index bbdf64e..64b3bdc 100644 (file)
@@ -5,7 +5,7 @@
        
 <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>
index 1bcb1d1..5d749a9 100644 (file)
@@ -5,7 +5,7 @@
        
 <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>
index d0e667a..3144e1c 100644 (file)
@@ -5,7 +5,7 @@
        
 <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>
diff --git a/configs/partialLogout.html b/configs/partialLogout.html
new file mode 100644 (file)
index 0000000..daafda6
--- /dev/null
@@ -0,0 +1,22 @@
+<?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>
index 2273174..fbfe9e5 100644 (file)
@@ -5,7 +5,7 @@
        
 <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>
index 388776f..43ff0e7 100644 (file)
             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"/>
index 2d25f3c..350d45a 100644 (file)
@@ -5,7 +5,7 @@
        
 <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>
index 889c5d3..c34dc0b 100644 (file)
@@ -162,6 +162,10 @@ if (Err = 0) then
     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
index 0f6c9ec..99c9be6 100644 (file)
                        <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
index c0aa136..7040500 100644 (file)
@@ -106,6 +106,7 @@ namespace shibsp {
             ) 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
@@ -121,6 +122,21 @@ namespace shibsp {
             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)
index 5768ac4..47345c7 100644 (file)
@@ -103,16 +103,15 @@ pair<bool,long> LocalLogoutInitiator::run(SPRequest& request, bool isHandler) co
     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");
 }
index 9f215dd..4c51a9d 100644 (file)
@@ -50,40 +50,32 @@ pair<bool,long> LogoutHandler::sendLogoutPage(
     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
index 984dc3c..d6931ce 100644 (file)
@@ -534,11 +534,18 @@ pair<bool,long> SAML2Logout::doRequest(const Application& application, const HTT
         // 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.");
index e6cb57e..24b8bfa 100644 (file)
@@ -289,7 +289,7 @@ pair<bool,long> SAML2LogoutInitiator::doRequest(
     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
@@ -324,7 +324,7 @@ pair<bool,long> SAML2LogoutInitiator::doRequest(
             }
         }
         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);
@@ -353,27 +353,32 @@ pair<bool,long> SAML2LogoutInitiator::doRequest(
                 }
             }
 
+            // 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) {