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.
24 * Handler for dumping information about an active session.
28 #include "Application.h"
29 #include "exceptions.h"
30 #include "ServiceProvider.h"
31 #include "SessionCache.h"
32 #include "SPRequest.h"
33 #include "attribute/Attribute.h"
34 #include "handler/SecuredHandler.h"
38 using namespace shibsp;
39 using namespace xmltooling;
44 #if defined (_MSC_VER)
45 #pragma warning( push )
46 #pragma warning( disable : 4250 )
49 class SHIBSP_API SessionHandler : public SecuredHandler
52 SessionHandler(const DOMElement* e, const char* appId);
53 virtual ~SessionHandler() {}
55 pair<bool,long> run(SPRequest& request, bool isHandler=true) const;
58 pair<bool,long> doHTML(SPRequest& request) const;
59 pair<bool,long> doJSON(SPRequest& request) const;
65 #if defined (_MSC_VER)
66 #pragma warning( pop )
69 Handler* SHIBSP_DLLLOCAL SessionHandlerFactory(const pair<const DOMElement*,const char*>& p)
71 return new SessionHandler(p.first, p.second);
76 SessionHandler::SessionHandler(const DOMElement* e, const char* appId)
77 : SecuredHandler(e, Category::getInstance(SHIBSP_LOGCAT ".SessionHandler")), m_values(false)
79 pair<bool,const char*> prop = getString("contentType");
81 m_contentType = prop.second;
82 if (!m_contentType.empty() && m_contentType != "application/json" && m_contentType != "text/html")
83 throw ConfigurationException("Unsupported contentType property in Session Handler configuration.");
85 pair<bool,bool> flag = getBool("showAttributeValues");
87 m_values = flag.second;
91 static ostream& json_safe(ostream& os, const char* buf)
125 pair<bool,long> SessionHandler::run(SPRequest& request, bool isHandler) const
127 // Check ACL in base class.
128 pair<bool,long> ret = SecuredHandler::run(request, isHandler);
131 request.setResponseHeader("Expires","Wed, 01 Jan 1997 12:00:00 GMT");
132 request.setResponseHeader("Cache-Control","private,no-store,no-cache,max-age=0");
133 if (m_contentType == "application/json") {
134 request.setContentType(m_contentType.c_str());
135 return doJSON(request);
137 request.setContentType("text/html; charset=UTF-8");
138 return doHTML(request);
141 pair<bool,long> SessionHandler::doJSON(SPRequest& request) const
145 Session* session = nullptr;
147 session = request.getSession(); // caches the locked session in the request so it's unlocked automatically
150 return make_pair(true, request.sendResponse(s));
153 catch (std::exception& ex) {
154 m_log.info("exception accessing user session: %s", ex.what());
156 return make_pair(true, request.sendError(s));
160 s << "\"expiration\": ";
161 if (session->getExpiration())
162 s << ((session->getExpiration() - time(nullptr)) / 60);
166 if (session->getClientAddress()) {
167 s << ", \"client_address\": ";
168 json_safe(s, session->getClientAddress());
171 if (session->getProtocol()) {
172 s << ", \"protocol\": ";
173 json_safe(s, session->getProtocol());
176 pair<bool,bool> stdvars = request.getRequestSettings().first->getBool("exportStdVars");
177 if (!stdvars.first || stdvars.second) {
178 if (session->getEntityID()) {
179 s << ", \"identity_provider\": ";
180 json_safe(s, session->getEntityID());
183 if (session->getAuthnInstant()) {
184 s << ", \"authn_instant\": ";
185 json_safe(s, session->getAuthnInstant());
188 if (session->getAuthnContextClassRef()) {
189 s << ", \"authncontext_class\": ";
190 json_safe(s, session->getAuthnContextClassRef());
193 if (session->getAuthnContextDeclRef()) {
194 s << ", \"authncontext_decl\": ";
195 json_safe(s, session->getAuthnContextDeclRef());
201 attributes: [ { "name": "foo", "values" : count } ]
204 { "name": "foo", "values": [ "val", "val" ] }
208 const multimap<string,const Attribute*>& attributes = session->getIndexedAttributes();
209 if (!attributes.empty()) {
210 s << ", \"attributes\": [ ";
212 vector<string>::size_type count=0;
213 for (multimap<string,const Attribute*>::const_iterator a = attributes.begin(); a != attributes.end(); ++a) {
214 if (a->first != key) {
215 // We're starting a new attribute.
216 if (a != attributes.begin()) {
217 // Need to close out the previous.
222 s << ", \"values\": " << count << " }, ";
227 json_safe(s, a->first.c_str());
231 const vector<string>& vals = a->second->getSerializedValues();
232 for (vector<string>::const_iterator v = vals.begin(); v!=vals.end(); ++v) {
233 if (v != vals.begin() || a->first == key) {
237 s << ", \"values\": [ ";
239 json_safe(s, v->c_str());
243 count += a->second->getSerializedValues().size();
251 s << ", \"values\": " << count << " }";
256 return make_pair(true, request.sendResponse(s));
259 pair<bool,long> SessionHandler::doHTML(SPRequest& request) const
262 s << "<html><head><title>Session Summary</title></head><body><pre>" << endl;
264 Session* session = nullptr;
266 session = request.getSession(); // caches the locked session in the request so it's unlocked automatically
268 s << "A valid session was not found.</pre></body></html>" << endl;
269 return make_pair(true, request.sendResponse(s));
272 catch (std::exception& ex) {
273 s << "Exception while retrieving active session:" << endl
274 << '\t' << ex.what() << "</pre></body></html>" << endl;
275 return make_pair(true, request.sendResponse(s));
278 s << "<u>Miscellaneous</u>" << endl;
280 s << "<strong>Session Expiration (barring inactivity):</strong> ";
281 if (session->getExpiration())
282 s << ((session->getExpiration() - time(nullptr)) / 60) << " minute(s)" << endl;
284 s << "Infinite" << endl;
286 s << "<strong>Client Address:</strong> " << (session->getClientAddress() ? session->getClientAddress() : "(none)") << endl;
287 s << "<strong>SSO Protocol:</strong> " << (session->getProtocol() ? session->getProtocol() : "(none)") << endl;
289 pair<bool,bool> stdvars = request.getRequestSettings().first->getBool("exportStdVars");
290 if (!stdvars.first || stdvars.second) {
291 s << "<strong>Identity Provider:</strong> " << (session->getEntityID() ? session->getEntityID() : "(none)") << endl;
292 s << "<strong>Authentication Time:</strong> " << (session->getAuthnInstant() ? session->getAuthnInstant() : "(none)") << endl;
293 s << "<strong>Authentication Context Class:</strong> " << (session->getAuthnContextClassRef() ? session->getAuthnContextClassRef() : "(none)") << endl;
294 s << "<strong>Authentication Context Decl:</strong> " << (session->getAuthnContextDeclRef() ? session->getAuthnContextDeclRef() : "(none)") << endl;
297 s << endl << "<u>Attributes</u>" << endl;
300 vector<string>::size_type count=0;
301 const multimap<string,const Attribute*>& attributes = session->getIndexedAttributes();
302 for (multimap<string,const Attribute*>::const_iterator a = attributes.begin(); a != attributes.end(); ++a) {
303 if (a->first != key) {
304 if (a != attributes.begin()) {
308 s << count << " value(s)" << endl;
312 s << "<strong>" << a->first << "</strong>: ";
316 const vector<string>& vals = a->second->getSerializedValues();
317 for (vector<string>::const_iterator v = vals.begin(); v!=vals.end(); ++v) {
318 if (v != vals.begin() || a->first == key)
320 string::size_type pos = v->find_first_of(';',string::size_type(0));
321 if (pos!=string::npos) {
323 for (; pos != string::npos; pos = value.find_first_of(';',pos)) {
324 value.insert(pos, "\\");
335 count += a->second->getSerializedValues().size();
340 if (!m_values && !attributes.empty())
341 s << count << " value(s)" << endl;
343 s << "</pre></body></html>";
344 return make_pair(true, request.sendResponse(s));