-/*
- * 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
+/**
+ * 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.
+ *
+ * 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.
*/
/**
* SessionHandler.cpp
- *
+ *
* Handler for dumping information about an active session.
*/
#include "SessionCache.h"
#include "SPRequest.h"
#include "attribute/Attribute.h"
-#include "handler/AbstractHandler.h"
+#include "handler/SecuredHandler.h"
#include <ctime>
#pragma warning( disable : 4250 )
#endif
- class SHIBSP_DLLLOCAL Blocker : public DOMNodeFilter
- {
- public:
- short acceptNode(const DOMNode* node) const {
- return FILTER_REJECT;
- }
- };
-
- static SHIBSP_DLLLOCAL Blocker g_Blocker;
-
- class SHIBSP_API SessionHandler : public AbstractHandler
+ class SHIBSP_API SessionHandler : public SecuredHandler
{
public:
SessionHandler(const DOMElement* e, const char* appId);
pair<bool,long> run(SPRequest& request, bool isHandler=true) const;
private:
+ pair<bool,long> doHTML(SPRequest& request) const;
+ pair<bool,long> doJSON(SPRequest& request) const;
+
bool m_values;
- set<string> m_acl;
+ string m_contentType;
};
#if defined (_MSC_VER)
};
SessionHandler::SessionHandler(const DOMElement* e, const char* appId)
- : AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT".SessionHandler"), &g_Blocker), m_values(false)
+ : SecuredHandler(e, Category::getInstance(SHIBSP_LOGCAT ".SessionHandler")), m_values(false)
{
- pair<bool,const char*> acl = getString("acl");
- if (acl.first) {
- string aclbuf=acl.second;
- int j = 0;
- for (unsigned int i=0; i < aclbuf.length(); i++) {
- if (aclbuf.at(i)==' ') {
- m_acl.insert(aclbuf.substr(j, i-j));
- j = i+1;
- }
- }
- m_acl.insert(aclbuf.substr(j, aclbuf.length()-j));
- }
+ pair<bool,const char*> prop = getString("contentType");
+ if (prop.first)
+ m_contentType = prop.second;
+ if (!m_contentType.empty() && m_contentType != "application/json" && m_contentType != "text/html")
+ throw ConfigurationException("Unsupported contentType property in Session Handler configuration.");
pair<bool,bool> flag = getBool("showAttributeValues");
if (flag.first)
m_values = flag.second;
}
+namespace {
+ static ostream& json_safe(ostream& os, const char* buf)
+ {
+ os << '"';
+ for (; *buf; ++buf) {
+ switch (*buf) {
+ case '\\':
+ case '"':
+ os << '\\';
+ os << *buf;
+ break;
+ case '\b':
+ os << "\\b";
+ break;
+ case '\t':
+ os << "\\t";
+ break;
+ case '\n':
+ os << "\\n";
+ break;
+ case '\f':
+ os << "\\f";
+ break;
+ case '\r':
+ os << "\\r";
+ break;
+ default:
+ os << *buf;
+ }
+ }
+ os << '"';
+ return os;
+ }
+};
+
pair<bool,long> SessionHandler::run(SPRequest& request, bool isHandler) const
{
- if (!m_acl.empty() && m_acl.count(request.getRemoteAddr()) == 0) {
- m_log.error("session handler request blocked from invalid address (%s)", request.getRemoteAddr().c_str());
- istringstream msg("Session Handler Blocked");
- return make_pair(true,request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_UNAUTHORIZED));
+ // Check ACL in base class.
+ pair<bool,long> ret = SecuredHandler::run(request, isHandler);
+ if (ret.first)
+ return ret;
+ request.setResponseHeader("Expires","Wed, 01 Jan 1997 12:00:00 GMT");
+ request.setResponseHeader("Cache-Control","private,no-store,no-cache,max-age=0");
+ if (m_contentType == "application/json") {
+ request.setContentType(m_contentType.c_str());
+ return doJSON(request);
+ }
+ request.setContentType("text/html; charset=UTF-8");
+ return doHTML(request);
+}
+
+pair<bool,long> SessionHandler::doJSON(SPRequest& request) const
+{
+ stringstream s;
+
+ Session* session = nullptr;
+ try {
+ session = request.getSession(); // caches the locked session in the request so it's unlocked automatically
+ if (!session) {
+ s << "{}" << endl;
+ return make_pair(true, request.sendResponse(s));
+ }
+ }
+ catch (std::exception& ex) {
+ m_log.info("exception accessing user session: %s", ex.what());
+ s << "{}" << endl;
+ return make_pair(true, request.sendError(s));
+ }
+
+ s << "{ ";
+ s << "\"expiration\": ";
+ if (session->getExpiration())
+ s << ((session->getExpiration() - time(nullptr)) / 60);
+ else
+ s << 0;
+
+ if (session->getClientAddress()) {
+ s << ", \"client_address\": ";
+ json_safe(s, session->getClientAddress());
+ }
+
+ if (session->getProtocol()) {
+ s << ", \"protocol\": ";
+ json_safe(s, session->getProtocol());
+ }
+
+ pair<bool,bool> stdvars = request.getRequestSettings().first->getBool("exportStdVars");
+ if (!stdvars.first || stdvars.second) {
+ if (session->getEntityID()) {
+ s << ", \"identity_provider\": ";
+ json_safe(s, session->getEntityID());
+ }
+
+ if (session->getAuthnInstant()) {
+ s << ", \"authn_instant\": ";
+ json_safe(s, session->getAuthnInstant());
+ }
+
+ if (session->getAuthnContextClassRef()) {
+ s << ", \"authncontext_class\": ";
+ json_safe(s, session->getAuthnContextClassRef());
+ }
+
+ if (session->getAuthnContextDeclRef()) {
+ s << ", \"authncontext_decl\": ";
+ json_safe(s, session->getAuthnContextDeclRef());
+ }
+
}
+ /*
+ attributes: [ { "name": "foo", "values" : count } ]
+
+ attributes: [
+ { "name": "foo", "values": [ "val", "val" ] }
+ ]
+ */
+
+ const multimap<string,const Attribute*>& attributes = session->getIndexedAttributes();
+ if (!attributes.empty()) {
+ s << ", \"attributes\": [ ";
+ string key;
+ vector<string>::size_type count=0;
+ for (multimap<string,const Attribute*>::const_iterator a = attributes.begin(); a != attributes.end(); ++a) {
+ if (a->first != key) {
+ // We're starting a new attribute.
+ if (a != attributes.begin()) {
+ // Need to close out the previous.
+ if (m_values) {
+ s << " ] }, ";
+ }
+ else {
+ s << ", \"values\": " << count << " }, ";
+ count = 0;
+ }
+ }
+ s << "{ \"name\": ";
+ json_safe(s, a->first.c_str());
+ }
+
+ if (m_values) {
+ const vector<string>& vals = a->second->getSerializedValues();
+ for (vector<string>::const_iterator v = vals.begin(); v!=vals.end(); ++v) {
+ if (v != vals.begin() || a->first == key) {
+ s << ", ";
+ }
+ else {
+ s << ", \"values\": [ ";
+ }
+ json_safe(s, v->c_str());
+ }
+ }
+ else {
+ count += a->second->getSerializedValues().size();
+ }
+ key = a->first;
+ }
+
+ if (m_values)
+ s << " ] } ";
+ else
+ s << ", \"values\": " << count << " }";
+ s << " ]";
+ }
+
+ s << " }" << endl;
+ return make_pair(true, request.sendResponse(s));
+}
+
+pair<bool,long> SessionHandler::doHTML(SPRequest& request) const
+{
stringstream s;
s << "<html><head><title>Session Summary</title></head><body><pre>" << endl;
- Session* session = request.getSession();
- if (!session) {
- s << "A valid session was not found.</pre></body></html>" << endl;
- request.setContentType("text/html");
- request.setResponseHeader("Expires","01-Jan-1997 12:00:00 GMT");
- request.setResponseHeader("Cache-Control","private,no-store,no-cache");
+ Session* session = nullptr;
+ try {
+ session = request.getSession(); // caches the locked session in the request so it's unlocked automatically
+ if (!session) {
+ s << "A valid session was not found.</pre></body></html>" << endl;
+ return make_pair(true, request.sendResponse(s));
+ }
+ }
+ catch (std::exception& ex) {
+ s << "Exception while retrieving active session:" << endl
+ << '\t' << ex.what() << "</pre></body></html>" << endl;
return make_pair(true, request.sendResponse(s));
}
s << "<u>Miscellaneous</u>" << endl;
- s << "<strong>Client Address</strong>: " << (session->getClientAddress() ? session->getClientAddress() : "(none)") << endl;
- s << "<strong>Identity Provider</strong>: " << (session->getEntityID() ? session->getEntityID() : "(none)") << endl;
- s << "<strong>SSO Protocol</strong>: " << (session->getProtocol() ? session->getProtocol() : "(none)") << endl;
- s << "<strong>Authentication Time</strong>: " << (session->getAuthnInstant() ? session->getAuthnInstant() : "(none)") << endl;
- s << "<strong>Authentication Context Class</strong>: " << (session->getAuthnContextClassRef() ? session->getAuthnContextClassRef() : "(none)") << endl;
- s << "<strong>Authentication Context Decl</strong>: " << (session->getAuthnContextDeclRef() ? session->getAuthnContextDeclRef() : "(none)") << endl;
- s << "<strong>Session Expiration (barring inactivity)</strong>: ";
+ s << "<strong>Session Expiration (barring inactivity):</strong> ";
if (session->getExpiration())
- s << ((session->getExpiration() - time(NULL)) / 60) << " minute(s)" << endl;
+ s << ((session->getExpiration() - time(nullptr)) / 60) << " minute(s)" << endl;
else
s << "Infinite" << endl;
-
+
+ s << "<strong>Client Address:</strong> " << (session->getClientAddress() ? session->getClientAddress() : "(none)") << endl;
+ s << "<strong>SSO Protocol:</strong> " << (session->getProtocol() ? session->getProtocol() : "(none)") << endl;
+
+ pair<bool,bool> stdvars = request.getRequestSettings().first->getBool("exportStdVars");
+ if (!stdvars.first || stdvars.second) {
+ s << "<strong>Identity Provider:</strong> " << (session->getEntityID() ? session->getEntityID() : "(none)") << endl;
+ s << "<strong>Authentication Time:</strong> " << (session->getAuthnInstant() ? session->getAuthnInstant() : "(none)") << endl;
+ s << "<strong>Authentication Context Class:</strong> " << (session->getAuthnContextClassRef() ? session->getAuthnContextClassRef() : "(none)") << endl;
+ s << "<strong>Authentication Context Decl:</strong> " << (session->getAuthnContextDeclRef() ? session->getAuthnContextDeclRef() : "(none)") << endl;
+ }
+
s << endl << "<u>Attributes</u>" << endl;
string key;
count = 0;
}
}
- s << "<strong>" << a->second->getId() << "</strong>: ";
+ s << "<strong>" << a->first << "</strong>: ";
}
if (m_values) {
else {
count += a->second->getSerializedValues().size();
}
+ key = a->first;
}
if (!m_values && !attributes.empty())
s << count << " value(s)" << endl;
-
+
s << "</pre></body></html>";
- request.setContentType("text/html; charset=UTF-8");
- request.setResponseHeader("Expires","01-Jan-1997 12:00:00 GMT");
- request.setResponseHeader("Cache-Control","private,no-store,no-cache");
return make_pair(true, request.sendResponse(s));
}