X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=shibsp%2Fhandler%2Fimpl%2FSessionHandler.cpp;h=ba8f71a60810ffc0be2a80a10e6070e864d644c0;hb=c51bfd77603cf0ddb0b5e374c35586a8435895d6;hp=813aad9911ac3458036cdd580e6f6a89136f8bfd;hpb=7a5cf4f75466e17263018c7b220e7f020774ba1b;p=shibboleth%2Fcpp-sp.git diff --git a/shibsp/handler/impl/SessionHandler.cpp b/shibsp/handler/impl/SessionHandler.cpp index 813aad9..ba8f71a 100644 --- a/shibsp/handler/impl/SessionHandler.cpp +++ b/shibsp/handler/impl/SessionHandler.cpp @@ -1,17 +1,21 @@ -/* - * Copyright 2001-2007 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. */ /** @@ -27,7 +31,7 @@ #include "SessionCache.h" #include "SPRequest.h" #include "attribute/Attribute.h" -#include "handler/AbstractHandler.h" +#include "handler/SecuredHandler.h" #include @@ -42,22 +46,7 @@ namespace shibsp { #pragma warning( disable : 4250 ) #endif - class SHIBSP_DLLLOCAL Blocker : public DOMNodeFilter - { - public: -#ifdef SHIBSP_XERCESC_SHORT_ACCEPTNODE - short -#else - FilterAction -#endif - 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); @@ -66,8 +55,11 @@ namespace shibsp { pair run(SPRequest& request, bool isHandler=true) const; private: + pair doHTML(SPRequest& request) const; + pair doJSON(SPRequest& request) const; + bool m_values; - set m_acl; + string m_contentType; }; #if defined (_MSC_VER) @@ -82,71 +74,226 @@ namespace shibsp { }; 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 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 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 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 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_FORBIDDEN)); + // Check ACL in base class. + pair 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 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 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& attributes = session->getIndexedAttributes(); + if (!attributes.empty()) { + s << ", \"attributes\": [ "; + string key; + vector::size_type count=0; + for (multimap::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& vals = a->second->getSerializedValues(); + for (vector::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 SessionHandler::doHTML(SPRequest& request) const +{ stringstream s; s << "Session Summary
" << endl;
 
-    Session* session = NULL;
+    Session* session = nullptr;
     try {
-        session = request.getSession();
+        session = request.getSession(); // caches the locked session in the request so it's unlocked automatically
         if (!session) {
             s << "A valid session was not found.
" << endl; - request.setContentType("text/html"); - 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)); } } - catch (exception& ex) { + catch (std::exception& ex) { s << "Exception while retrieving active session:" << endl << '\t' << ex.what() << "" << endl; - request.setContentType("text/html"); - 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)); } s << "Miscellaneous" << endl; - s << "Client Address: " << (session->getClientAddress() ? session->getClientAddress() : "(none)") << endl; - s << "Identity Provider: " << (session->getEntityID() ? session->getEntityID() : "(none)") << endl; - s << "SSO Protocol: " << (session->getProtocol() ? session->getProtocol() : "(none)") << endl; - s << "Authentication Time: " << (session->getAuthnInstant() ? session->getAuthnInstant() : "(none)") << endl; - s << "Authentication Context Class: " << (session->getAuthnContextClassRef() ? session->getAuthnContextClassRef() : "(none)") << endl; - s << "Authentication Context Decl: " << (session->getAuthnContextDeclRef() ? session->getAuthnContextDeclRef() : "(none)") << endl; s << "Session Expiration (barring inactivity): "; 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 << "Client Address: " << (session->getClientAddress() ? session->getClientAddress() : "(none)") << endl; + s << "SSO Protocol: " << (session->getProtocol() ? session->getProtocol() : "(none)") << endl; + + pair stdvars = request.getRequestSettings().first->getBool("exportStdVars"); + if (!stdvars.first || stdvars.second) { + s << "Identity Provider: " << (session->getEntityID() ? session->getEntityID() : "(none)") << endl; + s << "Authentication Time: " << (session->getAuthnInstant() ? session->getAuthnInstant() : "(none)") << endl; + s << "Authentication Context Class: " << (session->getAuthnContextClassRef() ? session->getAuthnContextClassRef() : "(none)") << endl; + s << "Authentication Context Decl: " << (session->getAuthnContextDeclRef() ? session->getAuthnContextDeclRef() : "(none)") << endl; + } + s << endl << "Attributes" << endl; string key; @@ -187,14 +334,12 @@ pair SessionHandler::run(SPRequest& request, bool isHandler) const else { count += a->second->getSerializedValues().size(); } + key = a->first; } if (!m_values && !attributes.empty()) s << count << " value(s)" << endl; s << ""; - 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)); }