SSPCPP-616 - clean up concatenated string literals
[shibboleth/cpp-sp.git] / shibsp / handler / impl / LogoutHandler.cpp
index 5d6b087..ae989ef 100644 (file)
@@ -1,17 +1,21 @@
-/*
- *  Copyright 2001-2009 Internet2
+/**
+ * Licensed to the University Corporation for Advanced Internet
+ * Development, Inc. (UCAID) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
  *
- * 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
+ * UCAID licenses this file to you 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
  *
- *     http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
  */
 
 /**
 #include "ServiceProvider.h"
 #include "SessionCache.h"
 #include "SPRequest.h"
+#include "TransactionLog.h"
 #include "handler/LogoutHandler.h"
 #include "util/TemplateParameters.h"
 
 #include <fstream>
+#include <boost/lexical_cast.hpp>
 #include <xmltooling/XMLToolingConfig.h>
 #include <xmltooling/util/PathResolver.h>
 #include <xmltooling/util/URLEncoder.h>
 
 using namespace shibsp;
 using namespace xmltooling;
+using namespace boost;
 using namespace std;
 
 LogoutHandler::LogoutHandler() : m_initiator(true)
@@ -59,14 +66,14 @@ pair<bool,long> LogoutHandler::sendLogoutPage(
 {
     string tname = string(type) + "Logout";
     const PropertySet* props = application.getPropertySet("Errors");
-    pair<bool,const char*> prop = props ? props->getString(tname.c_str()) : pair<bool,const char*>(false,NULL);
+    pair<bool,const char*> prop = props ? props->getString(tname.c_str()) : pair<bool,const char*>(false,nullptr);
     if (!prop.first) {
         tname += ".html";
         prop.second = tname.c_str();
     }
     response.setContentType("text/html");
-    response.setResponseHeader("Expires","01-Jan-1997 12:00:00 GMT");
-    response.setResponseHeader("Cache-Control","private,no-store,no-cache");
+    response.setResponseHeader("Expires","Wed, 01 Jan 1997 12:00:00 GMT");
+    response.setResponseHeader("Cache-Control","private,no-store,no-cache,max-age=0");
     string fname(prop.second);
     ifstream infile(XMLToolingConfig::getConfig().getPathResolver()->resolve(fname, PathResolver::XMLTOOLING_CFG_FILE).c_str());
     if (!infile)
@@ -96,17 +103,17 @@ pair<bool,long> LogoutHandler::run(SPRequest& request, bool isHandler) const
 
 void LogoutHandler::receive(DDF& in, ostream& out)
 {
-    DDF ret(NULL);
+    DDF ret(nullptr);
     DDFJanitor jout(ret);
     if (in["notify"].integer() != 1)
         throw ListenerException("Unsupported operation.");
 
     // Find application.
     const char* aid=in["application_id"].string();
-    const Application* app=aid ? SPConfig::getConfig().getServiceProvider()->getApplication(aid) : NULL;
+    const Application* app=aid ? SPConfig::getConfig().getServiceProvider()->getApplication(aid) : nullptr;
     if (!app) {
         // Something's horribly wrong.
-        Category::getInstance(SHIBSP_LOGCAT".Logout").error("couldn't find application (%s) for logout", aid ? aid : "(missing)");
+        Category::getInstance(SHIBSP_LOGCAT ".Logout").error("couldn't find application (%s) for logout", aid ? aid : "(missing)");
         throw ConfigurationException("Unable to locate application for logout, deleted?");
     }
 
@@ -150,35 +157,34 @@ pair<bool,long> LogoutHandler::notifyFrontChannel(
     loc = loc + (strchr(loc.c_str(),'?') ? '&' : '?') + "action=logout";
 
     // Now we create a second URL representing the return location back to us.
-    ostringstream locstr;
     const char* start = request.getRequestURL();
-    const char* end = strchr(start,'?');
-    string tempstr(start, end ? end-start : strlen(start));
+    const char* end = strchr(start, '?');
+    string locstr(start, end ? end - start : strlen(start));
 
     // Add a signal that we're coming back from notification and the next index.
-    locstr << tempstr << "?notifying=1&index=" << index;
+    locstr = locstr + "?notifying=1&index=" + lexical_cast<string>(index);
 
     // Add return if set.
     if (param)
-        locstr << "&return=" << encoder->encode(param);
+        locstr = 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)
-            locstr << '&' << p->first << '=' << encoder->encode(p->second.c_str());
+            locstr = locstr + '&' + p->first + '=' + encoder->encode(p->second.c_str());
     }
     else {
         for (vector<string>::const_iterator q = m_preserve.begin(); q!=m_preserve.end(); ++q) {
             param = request.getParameter(q->c_str());
             if (param)
-                locstr << '&' << *q << '=' << encoder->encode(param);
+                locstr = locstr + '&' + *q + '=' + encoder->encode(param);
         }
     }
 
     // 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()));
+    loc = loc + "&return=" + encoder->encode(locstr.c_str());
+    return make_pair(true, response.sendRedirect(loc.c_str()));
 }
 
 #ifndef SHIBSP_LITE
@@ -206,7 +212,6 @@ namespace {
             HTTPSOAPTransport* http = dynamic_cast<HTTPSOAPTransport*>(&transport);
             if (http) {
                 http->useChunkedEncoding(false);
-                http->setRequestHeader("User-Agent", PACKAGE_NAME);
                 http->setRequestHeader(PACKAGE_NAME, PACKAGE_VERSION);
             }
         }
@@ -219,7 +224,7 @@ bool LogoutHandler::notifyBackChannel(
     ) const
 {
     if (sessions.empty()) {
-        Category::getInstance(SHIBSP_LOGCAT".Logout").error("no sessions supplied to back channel notification method");
+        Category::getInstance(SHIBSP_LOGCAT ".Logout").error("no sessions supplied to back channel notification method");
         return false;
     }
 
@@ -230,13 +235,13 @@ bool LogoutHandler::notifyBackChannel(
 
     if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) {
 #ifndef SHIBSP_LITE
-        auto_ptr<Envelope> env(EnvelopeBuilder::buildEnvelope());
+        scoped_ptr<Envelope> env(EnvelopeBuilder::buildEnvelope());
         Body* body = BodyBuilder::buildBody();
         env->setBody(body);
         ElementProxy* msg = new AnyElementImpl(shibspconstants::SHIB2SPNOTIFY_NS, LogoutNotification);
         body->getUnknownXMLObjects().push_back(msg);
-        msg->setAttribute(xmltooling::QName(NULL, _type), local ? _local : _global);
-        for (vector<string>::const_iterator s = sessions.begin(); s!=sessions.end(); ++s) {
+        msg->setAttribute(xmltooling::QName(nullptr, _type), local ? _local : _global);
+        for (vector<string>::const_iterator s = sessions.begin(); s != sessions.end(); ++s) {
             auto_ptr_XMLCh temp(s->c_str());
             ElementProxy* child = new AnyElementImpl(shibspconstants::SHIB2SPNOTIFY_NS, SessionID);
             child->setTextContent(temp.get());
@@ -247,11 +252,11 @@ bool LogoutHandler::notifyBackChannel(
         SOAPNotifier soaper;
         while (!endpoint.empty()) {
             try {
-                soaper.send(*env.get(), SOAPTransport::Address(application.getId(), application.getId(), endpoint.c_str()));
+                soaper.send(*env, SOAPTransport::Address(application.getId(), application.getId(), endpoint.c_str()));
                 delete soaper.receive();
             }
-            catch (exception& ex) {
-                Category::getInstance(SHIBSP_LOGCAT".Logout").error("error notifying application of logout event: %s", ex.what());
+            catch (std::exception& ex) {
+                Category::getInstance(SHIBSP_LOGCAT ".Logout").error("error notifying application of logout event: %s", ex.what());
                 result = false;
             }
             soaper.reset();
@@ -273,9 +278,44 @@ bool LogoutHandler::notifyBackChannel(
         in.addmember("local").integer(1);
     DDF s = in.addmember("sessions").list();
     for (vector<string>::const_iterator i = sessions.begin(); i!=sessions.end(); ++i) {
-        DDF temp = DDF(NULL).string(i->c_str());
+        DDF temp = DDF(nullptr).string(i->c_str());
         s.add(temp);
     }
-    out=application.getServiceProvider().getListenerService()->send(in);
+    out = application.getServiceProvider().getListenerService()->send(in);
     return (out.integer() == 1);
 }
+
+#ifndef SHIBSP_LITE
+
+LogoutEvent* LogoutHandler::newLogoutEvent(
+    const Application& application, const xmltooling::HTTPRequest* request, const Session* session
+    ) const
+{
+    if (!SPConfig::getConfig().isEnabled(SPConfig::Logging))
+        return nullptr;
+    try {
+        auto_ptr<TransactionLog::Event> event(SPConfig::getConfig().EventManager.newPlugin(LOGOUT_EVENT, nullptr));
+        LogoutEvent* logout_event = dynamic_cast<LogoutEvent*>(event.get());
+        if (logout_event) {
+            logout_event->m_request = request;
+            logout_event->m_app = &application;
+            logout_event->m_binding = getString("Binding").second;
+            logout_event->m_session = session;
+            if (session) {
+                logout_event->m_nameID = session->getNameID();
+                logout_event->m_sessions.push_back(session->getID());
+            }
+            event.release();
+            return logout_event;
+        }
+        else {
+            Category::getInstance(SHIBSP_LOGCAT ".Logout").warn("unable to audit event, log event object was of an incorrect type");
+        }
+    }
+    catch (std::exception& ex) {
+        Category::getInstance(SHIBSP_LOGCAT ".Logout").warn("exception auditing event: %s", ex.what());
+    }
+    return nullptr;
+}
+
+#endif