Convert role lookups to find_if algorithm.
[shibboleth/sp.git] / shibsp / handler / impl / SAML2LogoutInitiator.cpp
index dac3946..eddd725 100644 (file)
@@ -45,7 +45,6 @@ using namespace opensaml;
 
 using namespace shibsp;
 using namespace xmltooling;
-using namespace log4cpp;
 using namespace std;
 
 namespace shibsp {
@@ -72,8 +71,14 @@ namespace shibsp {
         void receive(DDF& in, ostream& out);
         pair<bool,long> run(SPRequest& request, bool isHandler=true) const;
 
+#ifndef SHIBSP_LITE
+        const char* getType() const {
+            return "LogoutInitiator";
+        }
+#endif
+
     private:
-        pair<bool,long> doRequest(const Application& application, const char* requestURL, Session* session_id, HTTPResponse& httpResponse) const;
+        pair<bool,long> doRequest(const Application& application, const char* requestURL, Session* session, HTTPResponse& httpResponse) const;
 
         string m_appId;
 #ifndef SHIBSP_LITE
@@ -99,7 +104,7 @@ namespace shibsp {
 };
 
 SAML2LogoutInitiator::SAML2LogoutInitiator(const DOMElement* e, const char* appId)
-    : AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT".LogoutInitiator")), m_appId(appId),
+    : AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT".LogoutInitiator.SAML2")), m_appId(appId),
 #ifndef SHIBSP_LITE
         m_outgoing(NULL),
 #endif
@@ -198,7 +203,7 @@ pair<bool,long> SAML2LogoutInitiator::run(SPRequest& request, bool isHandler) co
     }
     else {
         // When not out of process, we remote the request.
-        Locker locker(session);
+        Locker locker(session, false);
         DDF out,in(m_address.c_str());
         DDFJanitor jin(in), jout(out);
         in.addmember("application_id").string(request.getApplication().getId());
@@ -249,9 +254,12 @@ void SAML2LogoutInitiator::receive(DDF& in, ostream& out)
         else {
              m_log.error("no NameID or issuing entityID found in session");
              session->unlock();
-             session = NULL;
              app->getServiceProvider().getSessionCache()->remove(in["session_id"].string(), *app);
-         }
+
+            // Clear the cookie.
+            pair<string,const char*> shib_cookie=app->getCookieNameProps("_shibsession_");
+            resp->setCookie(shib_cookie.first.c_str(), shib_cookie.second);
+        }
     }
     out << ret;
 #else
@@ -263,6 +271,10 @@ pair<bool,long> SAML2LogoutInitiator::doRequest(
     const Application& application, const char* requestURL, Session* session, HTTPResponse& response
     ) const
 {
+    // Clear the cookie.
+    pair<string,const char*> shib_cookie=application.getCookieNameProps("_shibsession_");
+    response.setCookie(shib_cookie.first.c_str(), shib_cookie.second);
+
     // Do back channel notification.
     vector<string> sessions(1, session->getID());
     if (!notifyBackChannel(application, requestURL, sessions, false)) {
@@ -283,7 +295,7 @@ pair<bool,long> SAML2LogoutInitiator::doRequest(
                 namedparams(1, "entityID", session->getEntityID())
                 );
         }
-        const IDPSSODescriptor* role = entity->getIDPSSODescriptor(samlconstants::SAML20P_NS);
+        const IDPSSODescriptor* role = find_if(entity->getIDPSSODescriptors(), isValidForProtocol(samlconstants::SAML20P_NS));
         if (!role) {
             throw MetadataException(
                 "Unable to locate SAML 2.0 IdP role for identity provider ($entityID).",
@@ -319,7 +331,7 @@ pair<bool,long> SAML2LogoutInitiator::doRequest(
                     auto_ptr_char dest((*epit)->getLocation());
 
                     SAML2SOAPClient client(soaper, false);
-                    client.sendSAML(msg, mcc, dest.get());
+                    client.sendSAML(msg, application.getId(), mcc, dest.get());
                     StatusResponseType* srt = client.receiveSAML();
                     if (!(logoutResponse = dynamic_cast<LogoutResponse*>(srt))) {
                         delete srt;
@@ -333,21 +345,31 @@ pair<bool,long> SAML2LogoutInitiator::doRequest(
             }
 
             if (!logoutResponse)
-                return sendLogoutPage(application, response, false, "Identity provider did not respond to logout request.");
-            if (!logoutResponse->getStatus() || !logoutResponse->getStatus()->getStatusCode() ||
+                ret = sendLogoutPage(application, response, false, "Identity provider did not respond to logout request.");
+            else if (!logoutResponse->getStatus() || !logoutResponse->getStatus()->getStatusCode() ||
                    !XMLString::equals(logoutResponse->getStatus()->getStatusCode()->getValue(), saml2p::StatusCode::SUCCESS)) {
                 delete logoutResponse;
-                return sendLogoutPage(application, response, false, "Identity provider returned a SAML error in response to logout request.");
+                ret = sendLogoutPage(application, response, false, "Identity provider returned a SAML error in response to logout request.");
+            }
+            else {
+                delete logoutResponse;
+                ret = sendLogoutPage(application, response, false, "Logout completed successfully.");
+            }
+
+            if (session) {
+                string session_id = session->getID();
+                session->unlock();
+                session = NULL;
+                application.getServiceProvider().getSessionCache()->remove(session_id.c_str(), application);
             }
-            delete logoutResponse;
-            return sendLogoutPage(application, response, false, "Logout completed successfully.");
+            return ret;
         }
 
         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, response, "signRequests");
+        ret.second = sendMessage(*encoder, msg.get(), NULL, dest.get(), role, application, response);
         ret.first = true;
         msg.release();  // freed by encoder
     }
@@ -390,7 +412,7 @@ LogoutRequest* SAML2LogoutInitiator::buildRequest(
 
     const NameID* nameid = session.getNameID();
     const PropertySet* relyingParty = application.getRelyingParty(dynamic_cast<EntityDescriptor*>(role.getParent()));
-    pair<bool,const char*> flag = relyingParty->getString("encryptRequests");
+    pair<bool,const char*> flag = relyingParty->getString("encryption");
     if (flag.first &&
         (!strcmp(flag.second, "true") || (encoder && !strcmp(flag.second, "front")) || (!encoder && !strcmp(flag.second, "back")))) {
         auto_ptr<EncryptedID> encrypted(EncryptedIDBuilder::buildEncryptedID());
@@ -407,32 +429,31 @@ LogoutRequest* SAML2LogoutInitiator::buildRequest(
 
     if (!encoder) {
         // No encoder being used, so sign for SOAP client manually.
-        flag = relyingParty->getString("signRequests");
+        flag = relyingParty->getString("signing");
         if (flag.first && (!strcmp(flag.second, "true") || !strcmp(flag.second, "back"))) {
             CredentialResolver* credResolver=application.getCredentialResolver();
             if (credResolver) {
                 Locker credLocker(credResolver);
                 // Fill in criteria to use.
                 MetadataCredentialCriteria mcc(role);
-                mcc.setUsage(CredentialCriteria::SIGNING_CREDENTIAL);
+                mcc.setUsage(Credential::SIGNING_CREDENTIAL);
                 pair<bool,const char*> keyName = relyingParty->getString("keyName");
                 if (keyName.first)
                     mcc.getKeyNames().insert(keyName.second);
-                pair<bool,const XMLCh*> sigalg = relyingParty->getXMLString("signatureAlg");
+                pair<bool,const XMLCh*> sigalg = relyingParty->getXMLString("signingAlg");
                 if (sigalg.first)
                     mcc.setXMLAlgorithm(sigalg.second);
                 const Credential* cred = credResolver->resolve(&mcc);
                 if (cred) {
                     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) {
+                    if (sigalg.first)
+                        sig->setSignatureAlgorithm(sigalg.second);
+                    sigalg = relyingParty->getXMLString("digestAlg");
+                    if (sigalg.first) {
                         ContentReference* cr = dynamic_cast<ContentReference*>(sig->getContentReference());
                         if (cr)
-                            cr->setDigestAlgorithm(alg.second);
+                            cr->setDigestAlgorithm(sigalg.second);
                     }
             
                     // Sign response while marshalling.