Fix init order warning.
[shibboleth/cpp-sp.git] / shibsp / handler / impl / SAML2LogoutInitiator.cpp
index 9896d3a..bb5efd1 100644 (file)
@@ -53,8 +53,6 @@ using namespace opensaml;
 # include "lite/SAMLConstants.h"
 #endif
 
-#include <boost/scoped_ptr.hpp>
-
 using namespace shibsp;
 using namespace xmltooling;
 using namespace boost;
@@ -89,6 +87,7 @@ namespace shibsp {
             ) const;
 
         string m_appId;
+        auto_ptr_char m_protocol;
 #ifndef SHIBSP_LITE
         auto_ptr<LogoutRequest> buildRequest(
             const Application& application, const Session& session, const RoleDescriptor& role, const MessageEncoder* encoder=nullptr
@@ -103,10 +102,10 @@ namespace shibsp {
             return e;
         }
 
+        bool m_async;
         vector<string> m_bindings;
         map< string,boost::shared_ptr<MessageEncoder> > m_encoders;
 #endif
-        auto_ptr_char m_protocol;
     };
 
 #if defined (_MSC_VER)
@@ -121,6 +120,9 @@ namespace shibsp {
 
 SAML2LogoutInitiator::SAML2LogoutInitiator(const DOMElement* e, const char* appId)
     : AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT".LogoutInitiator.SAML2")), m_appId(appId), m_protocol(samlconstants::SAML20P_NS)
+#ifndef SHIBSP_LITE
+        ,m_async(true)
+#endif
 {
     // If Location isn't set, defer initialization until the setParent call.
     pair<bool,const char*> loc = getString("Location");
@@ -148,6 +150,9 @@ void SAML2LogoutInitiator::init(const char* location)
 
 #ifndef SHIBSP_LITE
     if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) {
+        pair<bool,bool> async = getBool("asynchronous");
+        m_async = !async.first || async.second;
+
         string dupBindings;
         pair<bool,const char*> outgoing = getString("outgoingBindings");
         if (outgoing.first) {
@@ -358,6 +363,7 @@ pair<bool,long> SAML2LogoutInitiator::doRequest(
                         logout_event->m_logoutType = LogoutEvent::LOGOUT_EVENT_UNKNOWN;
                         logout_event->m_saml2Request = msg.get();
                         application.getServiceProvider().getTransactionLog()->write(*logout_event);
+                        logout_event->m_saml2Request = nullptr;
                     }
 
                     auto_ptr_char dest(epit->getLocation());
@@ -410,11 +416,21 @@ pair<bool,long> SAML2LogoutInitiator::doRequest(
                 else {
                     const char* returnloc = httpRequest.getParameter("return");
                     if (returnloc) {
-                        limitRelayState(m_log, application, httpRequest, returnloc);
-                        ret.second = httpResponse.sendRedirect(returnloc);
+                        // Relative URLs get promoted, absolutes get validated.
+                        if (*returnloc == '/') {
+                            string loc(returnloc);
+                            httpRequest.absolutize(loc);
+                            ret.second = httpResponse.sendRedirect(loc.c_str());
+                        }
+                        else {
+                            application.limitRedirect(httpRequest, returnloc);
+                            ret.second = httpResponse.sendRedirect(returnloc);
+                        }
                         ret.first = true;
                     }
-                    ret = sendLogoutPage(application, httpRequest, httpResponse, "global");
+                    else {
+                        ret = sendLogoutPage(application, httpRequest, httpResponse, "global");
+                    }
                 }
             }
 
@@ -431,8 +447,10 @@ pair<bool,long> SAML2LogoutInitiator::doRequest(
         string relayState;
         const char* returnloc = httpRequest.getParameter("return");
         if (returnloc) {
-            limitRelayState(m_log, application, httpRequest, returnloc);
+            application.limitRedirect(httpRequest, returnloc);
             relayState = returnloc;
+            httpRequest.absolutize(relayState);
+            cleanRelayState(application, httpRequest, httpResponse);
             preserveRelayState(application, httpResponse, relayState);
         }
 
@@ -510,9 +528,16 @@ auto_ptr<LogoutRequest> SAML2LogoutInitiator::buildRequest(
         msg->setNameID(nameid->cloneNameID());
     }
 
-    msg->setID(SAMLConfig::getConfig().generateIdentifier());
+    XMLCh* msgid = SAMLConfig::getConfig().generateIdentifier();
+    msg->setID(msgid);
+    XMLString::release(&msgid);
     msg->setIssueInstant(time(nullptr));
 
+    if (m_async && encoder) {
+        msg->setExtensions(saml2p::ExtensionsBuilder::buildExtensions());
+        msg->getExtensions()->getUnknownXMLObjects().push_back(AsynchronousBuilder::buildAsynchronous());
+    }
+
     return msg;
 }