2 * Licensed to the University Corporation for Advanced Internet
3 * Development, Inc. (UCAID) under one or more contributor license
4 * agreements. See the NOTICE file distributed with this work for
5 * additional information regarding copyright ownership.
7 * UCAID licenses this file to you under the Apache License,
8 * Version 2.0 (the "License"); you may not use this file except
9 * in compliance with the License. You may obtain a copy of the
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17 * either express or implied. See the License for the specific
18 * language governing permissions and limitations under the License.
22 * LocalLogoutInitiator.cpp
24 * Logs out a session locally.
28 #include "exceptions.h"
29 #include "Application.h"
30 #include "ServiceProvider.h"
31 #include "SessionCache.h"
32 #include "SPRequest.h"
33 #include "handler/AbstractHandler.h"
34 #include "handler/LogoutInitiator.h"
37 using namespace boost;
40 using namespace shibsp;
41 using namespace xmltooling;
46 #if defined (_MSC_VER)
47 #pragma warning( push )
48 #pragma warning( disable : 4250 )
51 class SHIBSP_DLLLOCAL LocalLogoutInitiator : public AbstractHandler, public LogoutInitiator
54 LocalLogoutInitiator(const DOMElement* e, const char* appId);
55 virtual ~LocalLogoutInitiator() {}
57 void setParent(const PropertySet* parent);
58 void receive(DDF& in, ostream& out);
59 pair<bool,long> run(SPRequest& request, bool isHandler=true) const;
62 pair<bool,long> doRequest(
63 const Application& application, const HTTPRequest& request, HTTPResponse& httpResponse, Session* session
69 #if defined (_MSC_VER)
70 #pragma warning( pop )
73 Handler* SHIBSP_DLLLOCAL LocalLogoutInitiatorFactory(const pair<const DOMElement*,const char*>& p)
75 return new LocalLogoutInitiator(p.first, p.second);
79 LocalLogoutInitiator::LocalLogoutInitiator(const DOMElement* e, const char* appId)
80 : AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT".LogoutInitiator.Local")), m_appId(appId)
82 pair<bool,const char*> loc = getString("Location");
84 string address = string(appId) + loc.second + "::run::LocalLI";
85 setAddress(address.c_str());
89 void LocalLogoutInitiator::setParent(const PropertySet* parent)
91 DOMPropertySet::setParent(parent);
92 pair<bool,const char*> loc = getString("Location");
94 string address = m_appId + loc.second + "::run::LocalLI";
95 setAddress(address.c_str());
98 m_log.warn("no Location property in Local LogoutInitiator (or parent), can't register as remoted handler");
102 pair<bool,long> LocalLogoutInitiator::run(SPRequest& request, bool isHandler) const
104 // Defer to base class first.
105 pair<bool,long> ret = LogoutHandler::run(request, isHandler);
109 if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) {
110 // When out of process, we run natively.
111 Session* session = nullptr;
113 session = request.getSession(false, true, false); // don't cache it and ignore all checks
115 catch (std::exception& ex) {
116 m_log.error("error accessing current session: %s", ex.what());
118 return doRequest(request.getApplication(), request, request, session);
121 // When not out of process, we remote the request.
122 vector<string> headers(1,"Cookie");
123 headers.push_back("User-Agent");
124 DDF out,in = wrap(request,&headers);
125 DDFJanitor jin(in), jout(out);
126 out=request.getServiceProvider().getListenerService()->send(in);
127 return unwrap(request, out);
131 void LocalLogoutInitiator::receive(DDF& in, ostream& out)
134 // Defer to base class for back channel notifications
135 if (in["notify"].integer() == 1)
136 return LogoutHandler::receive(in, out);
139 const char* aid=in["application_id"].string();
140 const Application* app=aid ? SPConfig::getConfig().getServiceProvider()->getApplication(aid) : nullptr;
142 // Something's horribly wrong.
143 m_log.error("couldn't find application (%s) for logout", aid ? aid : "(missing)");
144 throw ConfigurationException("Unable to locate application for logout, deleted?");
147 // Unpack the request.
148 scoped_ptr<HTTPRequest> req(getRequest(in));
150 // Set up a response shim.
152 DDFJanitor jout(ret);
153 scoped_ptr<HTTPResponse> resp(getResponse(ret));
155 Session* session = nullptr;
157 session = app->getServiceProvider().getSessionCache()->find(*app, *req, nullptr, nullptr);
159 catch (std::exception& ex) {
160 m_log.error("error accessing current session: %s", ex.what());
163 // This is the "last chance" handler so even without a session, we "complete" the logout.
164 doRequest(*app, *req, *resp, session);
168 throw ConfigurationException("Cannot perform logout using lite version of shibsp library.");
172 pair<bool,long> LocalLogoutInitiator::doRequest(
173 const Application& application, const HTTPRequest& httpRequest, HTTPResponse& httpResponse, Session* session
177 // Guard the session in case of exception.
178 Locker locker(session, false);
180 // Do back channel notification.
182 vector<string> sessions(1, session->getID());
183 result = notifyBackChannel(application, httpRequest.getRequestURL(), sessions, true);
185 scoped_ptr<LogoutEvent> logout_event(newLogoutEvent(application, &httpRequest, session));
187 logout_event->m_logoutType = result ? LogoutEvent::LOGOUT_EVENT_LOCAL : LogoutEvent::LOGOUT_EVENT_PARTIAL;
188 application.getServiceProvider().getTransactionLog()->write(*logout_event);
191 locker.assign(); // unlock the session
192 application.getServiceProvider().getSessionCache()->remove(application, httpRequest, &httpResponse);
194 return sendLogoutPage(application, httpRequest, httpResponse, "partial");
197 // Route back to return location specified, or use the local template.
198 const char* dest = httpRequest.getParameter("return");
200 // Relative URLs get promoted, absolutes get validated.
203 httpRequest.absolutize(d);
204 return make_pair(true, httpResponse.sendRedirect(d.c_str()));
206 application.limitRedirect(httpRequest, dest);
207 return make_pair(true, httpResponse.sendRedirect(dest));
209 return sendLogoutPage(application, httpRequest, httpResponse, "local");