Move back channel notify loop out of base class for better control.
[shibboleth/sp.git] / shibsp / handler / impl / SAML2LogoutInitiator.cpp
index c60ad96..4a0f630 100644 (file)
@@ -166,11 +166,14 @@ void SAML2LogoutInitiator::setParent(const PropertySet* parent)
 
 pair<bool,long> SAML2LogoutInitiator::run(SPRequest& request, bool isHandler) const
 {
-    // Defer to base class first.
+    // Defer to base class for front-channel loop first.
     pair<bool,long> ret = LogoutHandler::run(request, isHandler);
     if (ret.first)
         return ret;
 
+    // At this point we know the front-channel is handled.
+    // We need the session to do any other work.
+
     Session* session = NULL;
     try {
         session = request.getSession(false, true, false);  // don't cache it and ignore all checks
@@ -178,16 +181,16 @@ pair<bool,long> SAML2LogoutInitiator::run(SPRequest& request, bool isHandler) co
             return make_pair(false,0);
 
         // We only handle SAML 2.0 sessions.
-        if (!XMLString::equals(session->getProtocol(), m_protocol.get()))
+        if (!XMLString::equals(session->getProtocol(), m_protocol.get())) {
+            session->unlock();
             return make_pair(false,0);
+        }
     }
     catch (exception& ex) {
         m_log.error("error accessing current session: %s", ex.what());
         return make_pair(false,0);
     }
 
-    // At this point, notification is completed, and we're ready to issue a LogoutRequest.
-
     if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) {
         // When out of process, we run natively.
         return doRequest(request.getApplication(), session, request);
@@ -256,6 +259,14 @@ void SAML2LogoutInitiator::receive(DDF& in, ostream& out)
 
 pair<bool,long> SAML2LogoutInitiator::doRequest(const Application& application, Session* session, HTTPResponse& response) const
 {
+    // Do back channel notification.
+    vector<string> sessions(1, session->getID());
+    if (!notifyBackChannel(application, sessions)) {
+        session->unlock();
+        application.getServiceProvider().getSessionCache()->remove(sessions.front().c_str(), application);
+        return sendLogoutPage(application, response, true, "Partial logout failure.");
+    }
+
 #ifndef SHIBSP_LITE
     pair<bool,long> ret = make_pair(false,0);
     try {
@@ -408,21 +419,21 @@ LogoutRequest* SAML2LogoutInitiator::buildRequest(
                     mcc.setXMLAlgorithm(sigalg.second);
                 const Credential* cred = credResolver->resolve(&mcc);
                 if (cred) {
-                    xmlsignature::Signature* sig = xmlsignature::SignatureBuilder::buildSignature();\r
-                    msg->setSignature(sig);\r
-                    pair<bool, const XMLCh*> alg = relyingParty->getXMLString("signatureAlg");\r
-                    if (alg.first)\r
-                        sig->setSignatureAlgorithm(alg.second);\r
-                    alg = relyingParty->getXMLString("digestAlg");\r
-                    if (alg.first) {\r
-                        ContentReference* cr = dynamic_cast<ContentReference*>(sig->getContentReference());\r
-                        if (cr)\r
-                            cr->setDigestAlgorithm(alg.second);\r
-                    }\r
-            \r
-                    // Sign response while marshalling.\r
-                    vector<xmlsignature::Signature*> sigs(1,sig);\r
-                    msg->marshall((DOMDocument*)NULL,&sigs,cred);\r
+                    xmlsignature::Signature* sig = xmlsignature::SignatureBuilder::buildSignature();
+                    msg->setSignature(sig);
+                    pair<bool, const XMLCh*> alg = relyingParty->getXMLString("signatureAlg");
+                    if (alg.first)
+                        sig->setSignatureAlgorithm(alg.second);
+                    alg = relyingParty->getXMLString("digestAlg");
+                    if (alg.first) {
+                        ContentReference* cr = dynamic_cast<ContentReference*>(sig->getContentReference());
+                        if (cr)
+                            cr->setDigestAlgorithm(alg.second);
+                    }
+            
+                    // Sign response while marshalling.
+                    vector<xmlsignature::Signature*> sigs(1,sig);
+                    msg->marshall((DOMDocument*)NULL,&sigs,cred);
                 }
                 else {
                     m_log.warn("no signing credential resolved, leaving message unsigned");