Add return parameter and relay state support to logout processing in lieu of templates.
authorcantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Wed, 19 Dec 2007 23:18:32 +0000 (23:18 +0000)
committercantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Wed, 19 Dec 2007 23:18:32 +0000 (23:18 +0000)
git-svn-id: https://svn.middleware.georgetown.edu/cpp-sp/trunk@2679 cb58f699-b61c-0410-a6fe-9272a202ed29

configs/shibboleth2.xml.in
schemas/shibboleth-2.0-native-sp-config.xsd
shibsp/handler/impl/LocalLogoutInitiator.cpp
shibsp/handler/impl/LogoutHandler.cpp
shibsp/handler/impl/SAML2Logout.cpp
shibsp/handler/impl/SAML2LogoutInitiator.cpp

index c7ac88a..bd35126 100644 (file)
                 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>
index c08d2b4..fb2d538 100644 (file)
                                                <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
index 832e640..6850bec 100644 (file)
@@ -109,5 +109,9 @@ pair<bool,long> LocalLogoutInitiator::run(SPRequest& request, bool isHandler) co
         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.");
 }
index c86b412..5342397 100644 (file)
@@ -119,6 +119,9 @@ pair<bool,long> LogoutHandler::notifyFrontChannel(
     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())
@@ -138,6 +141,10 @@ pair<bool,long> LogoutHandler::notifyFrontChannel(
     // 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)
@@ -151,7 +158,8 @@ pair<bool,long> LogoutHandler::notifyFrontChannel(
         }
     }
 
-    // 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()));
 }
index ade83f0..7dd1d78 100644 (file)
@@ -514,6 +514,12 @@ pair<bool,long> SAML2Logout::doRequest(const Application& application, const HTT
         }
         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.");
     }
index 00a1a66..ff813d3 100644 (file)
@@ -348,6 +348,11 @@ pair<bool,long> SAML2LogoutInitiator::doRequest(
             }
             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.");
             }
 
@@ -359,11 +364,19 @@ pair<bool,long> SAML2LogoutInitiator::doRequest(
             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
     }