Imported Upstream version 2.1.dfsg1
[shibboleth/sp.git] / shibsp / handler / impl / SAML2LogoutInitiator.cpp
index 400989c..e5a6bbb 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Copyright 2001-2007 Internet2
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -16,7 +16,7 @@
 
 /**
  * SAML2LogoutInitiator.cpp
- * 
+ *
  * Triggers SP-initiated logout for SAML 2.0 sessions.
  */
 
@@ -30,6 +30,7 @@
 
 #ifndef SHIBSP_LITE
 # include "binding/SOAPClient.h"
+# include "metadata/MetadataProviderCriteria.h"
 # include <saml/SAMLConfig.h>
 # include <saml/saml2/core/Protocols.h>
 # include <saml/saml2/binding/SAML2SOAPClient.h>
@@ -53,7 +54,7 @@ namespace shibsp {
     #pragma warning( push )
     #pragma warning( disable : 4250 )
 #endif
-    
+
     class SHIBSP_DLLLOCAL SAML2LogoutInitiator : public AbstractHandler, public LogoutHandler
     {
     public:
@@ -66,7 +67,7 @@ namespace shibsp {
             }
 #endif
         }
-        
+
         void setParent(const PropertySet* parent);
         void receive(DDF& in, ostream& out);
         pair<bool,long> run(SPRequest& request, bool isHandler=true) const;
@@ -229,7 +230,7 @@ void SAML2LogoutInitiator::receive(DDF& in, ostream& out)
         m_log.error("couldn't find application (%s) for logout", aid ? aid : "(missing)");
         throw ConfigurationException("Unable to locate application for logout, deleted?");
     }
-    
+
     // Unpack the request.
     auto_ptr<HTTPRequest> req(getRequest(in));
 
@@ -237,7 +238,7 @@ void SAML2LogoutInitiator::receive(DDF& in, ostream& out)
     DDF ret(NULL);
     DDFJanitor jout(ret);
     auto_ptr<HTTPResponse> resp(getResponse(ret));
-    
+
     Session* session = NULL;
     try {
          session = app->getServiceProvider().getSessionCache()->find(*app, *req.get(), NULL, NULL);
@@ -284,7 +285,7 @@ pair<bool,long> SAML2LogoutInitiator::doRequest(
         // With a session in hand, we can create a LogoutRequest message, if we can find a compatible endpoint.
         MetadataProvider* m = application.getMetadataProvider();
         Locker metadataLocker(m);
-        MetadataProvider::Criteria mc(session->getEntityID(), &IDPSSODescriptor::ELEMENT_QNAME, samlconstants::SAML20P_NS);
+        MetadataProviderCriteria mc(application, session->getEntityID(), &IDPSSODescriptor::ELEMENT_QNAME, samlconstants::SAML20P_NS);
         pair<const EntityDescriptor*,const RoleDescriptor*> entity = m->getEntityDescriptor(mc);
         if (!entity.first) {
             throw MetadataException(
@@ -339,8 +340,14 @@ pair<bool,long> SAML2LogoutInitiator::doRequest(
                 }
             }
 
-            if (!logoutResponse)
-                ret = sendLogoutPage(application, httpRequest, httpResponse, false, "Identity provider did not respond to logout request.");
+            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."
+                    );
+            }
             else if (!logoutResponse->getStatus() || !logoutResponse->getStatus()->getStatusCode() ||
                    !XMLString::equals(logoutResponse->getStatus()->getStatusCode()->getValue(), saml2p::StatusCode::SUCCESS)) {
                 delete logoutResponse;
@@ -432,6 +439,9 @@ LogoutRequest* SAML2LogoutInitiator::buildRequest(
             );
         msg->setEncryptedID(encrypted.release());
     }
+    else {
+        msg->setNameID(nameid->cloneNameID());
+    }
 
     if (!encoder) {
         // No encoder being used, so sign for SOAP client manually.
@@ -461,7 +471,7 @@ LogoutRequest* SAML2LogoutInitiator::buildRequest(
                         if (cr)
                             cr->setDigestAlgorithm(sigalg.second);
                     }
-            
+
                     // Sign response while marshalling.
                     vector<xmlsignature::Signature*> sigs(1,sig);
                     msg->marshall((DOMDocument*)NULL,&sigs,cred);