Session dumping handler.
authorcantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Mon, 19 Nov 2007 04:20:48 +0000 (04:20 +0000)
committercantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Mon, 19 Nov 2007 04:20:48 +0000 (04:20 +0000)
Add expiration accessor to sessions.

git-svn-id: https://svn.middleware.georgetown.edu/cpp-sp/trunk@2629 cb58f699-b61c-0410-a6fe-9272a202ed29

configs/shibboleth2.xml.in
schemas/shibboleth-2.0-native-sp-config.xsd
shibsp/Makefile.am
shibsp/SessionCache.h
shibsp/handler/Handler.h
shibsp/handler/impl/AbstractHandler.cpp
shibsp/handler/impl/SessionHandler.cpp [new file with mode: 0644]
shibsp/impl/RemotedSessionCache.cpp
shibsp/impl/StorageServiceSessionCache.cpp
shibsp/shibsp-lite.vcproj
shibsp/shibsp.vcproj

index be31bc7..20afc4e 100644 (file)
             <!-- Status reporting service. -->
             <Handler type="Status" Location="/Status" acl="127.0.0.1"/>
 
+            <!-- Session diagnostic service. -->
+            <Handler type="Session" Location="/Session"/>
+
                </Sessions>
 
                <!--
index 55c3d71..c187fd3 100644 (file)
                                                                        <any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>\r
                                                                </sequence>\r
                                                                <attribute name="Location" type="anyURI" use="required"/>\r
+                                                           <attribute name="acl" type="conf:listOfStrings"/>\r
                                                                <anyAttribute namespace="##any" processContents="lax"/>\r
                                                        </restriction>\r
                                                </complexContent>\r
index 41e588a..7a55bc8 100644 (file)
@@ -116,6 +116,7 @@ common_sources = \
        handler/impl/MetadataGenerator.cpp \
        handler/impl/RemotedHandler.cpp \
        handler/impl/StatusHandler.cpp \
+       handler/impl/SessionHandler.cpp \
        handler/impl/SAML1Consumer.cpp \
        handler/impl/SAML2Consumer.cpp \
        handler/impl/SAML2ArtifactResolution.cpp \
index ad3a20c..49a334e 100644 (file)
@@ -51,6 +51,20 @@ namespace shibsp {
         virtual const char* getID() const=0;
 
         /**
+         * Returns the session expiration.
+         *
+         * @return  the session's expiration time or 0 for none
+         */
+        virtual time_t getExpiration() const=0;
+
+        /**
+         * Returns the last access time of the session.
+         *
+         * @return  the session's last access time
+         */
+        virtual time_t getLastAccess() const=0;
+
+        /**
          * Returns the address of the client associated with the session.
          * 
          * @return  the client's network address
index f826882..a73b1ff 100644 (file)
@@ -80,6 +80,15 @@ namespace shibsp {
     
     /** Registers Handler implementations. */
     void SHIBSP_API registerHandlers();
+
+    /** Handler for metadata generation. */
+    #define METADATA_GENERATOR_HANDLER "MetadataGenerator"
+
+    /** Handler for status information. */
+    #define STATUS_HANDLER "Status"
+
+    /** Handler for session diagnostic information. */
+    #define SESSION_HANDLER "Session"
 };
 
 #endif /* __shibsp_handler_h__ */
index e1f3801..301ae06 100644 (file)
@@ -66,6 +66,7 @@ namespace shibsp {
     SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory AssertionLookupFactory;
     SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory MetadataGeneratorFactory;
     SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory StatusHandlerFactory;
+    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SessionHandlerFactory;
 };
 
 void SHIBSP_API shibsp::registerHandlers()
@@ -82,8 +83,9 @@ void SHIBSP_API shibsp::registerHandlers()
     conf.ArtifactResolutionServiceManager.registerFactory(SAML20_BINDING_SOAP, SAML2ArtifactResolutionFactory);
 
     conf.HandlerManager.registerFactory(SAML20_BINDING_URI, AssertionLookupFactory);
-    conf.HandlerManager.registerFactory("MetadataGenerator", MetadataGeneratorFactory);
-    conf.HandlerManager.registerFactory("Status", StatusHandlerFactory);
+    conf.HandlerManager.registerFactory(METADATA_GENERATOR_HANDLER, MetadataGeneratorFactory);
+    conf.HandlerManager.registerFactory(STATUS_HANDLER, StatusHandlerFactory);
+    conf.HandlerManager.registerFactory(SESSION_HANDLER, SessionHandlerFactory);
 
     conf.LogoutInitiatorManager.registerFactory(CHAINING_LOGOUT_INITIATOR, ChainingLogoutInitiatorFactory);
     conf.LogoutInitiatorManager.registerFactory(LOCAL_LOGOUT_INITIATOR, LocalLogoutInitiatorFactory);
diff --git a/shibsp/handler/impl/SessionHandler.cpp b/shibsp/handler/impl/SessionHandler.cpp
new file mode 100644 (file)
index 0000000..72951bf
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ *  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
+ *
+ *     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.
+ */
+
+/**
+ * SessionHandler.cpp
+ * 
+ * Handler for dumping information about an active session.
+ */
+
+#include "internal.h"
+#include "Application.h"
+#include "exceptions.h"
+#include "ServiceProvider.h"
+#include "SessionCache.h"
+#include "SPRequest.h"
+#include "attribute/Attribute.h"
+#include "handler/AbstractHandler.h"
+
+#include <ctime>
+
+using namespace shibsp;
+using namespace xmltooling;
+using namespace std;
+
+namespace shibsp {
+
+#if defined (_MSC_VER)
+    #pragma warning( push )
+    #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
+    {
+    public:
+        SessionHandler(const DOMElement* e, const char* appId);
+        virtual ~SessionHandler() {}
+
+        pair<bool,long> run(SPRequest& request, bool isHandler=true) const;
+
+    private:
+        bool m_values;
+        set<string> m_acl;
+    };
+
+#if defined (_MSC_VER)
+    #pragma warning( pop )
+#endif
+
+    Handler* SHIBSP_DLLLOCAL SessionHandlerFactory(const pair<const DOMElement*,const char*>& p)
+    {
+        return new SessionHandler(p.first, p.second);
+    }
+
+};
+
+SessionHandler::SessionHandler(const DOMElement* e, const char* appId)
+    : AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT".SessionHandler"), &g_Blocker), 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,bool> flag = getBool("showAttributeValues");
+    if (flag.first)
+        m_values = flag.second;
+}
+
+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));
+    }
+
+    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");
+        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>: ";
+    if (session->getExpiration())
+        s << ((session->getExpiration() - time(NULL)) / 60) << " minute(s)" << endl;
+    else
+        s << "Infinite" << endl;
+    
+    s << endl << "<u>Attributes</u>" << endl;
+
+    string key;
+    vector<string>::size_type count=0;
+    const multimap<string,const Attribute*>& attributes = session->getIndexedAttributes();
+    for (multimap<string,const Attribute*>::const_iterator a = attributes.begin(); a != attributes.end(); ++a) {
+        if (a->first != key) {
+            if (a != attributes.begin()) {
+                if (m_values)
+                    s << endl;
+                else {
+                    s << count << " value(s)" << endl;
+                    count = 0;
+                }
+            }
+            s << "<strong>" << a->second->getId() << "</strong>: ";
+        }
+
+        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 << ';';
+                string::size_type pos = v->find_first_of(';',string::size_type(0));
+                if (pos!=string::npos) {
+                    string value(*v);
+                    for (; pos != string::npos; pos = value.find_first_of(';',pos)) {
+                        value.insert(pos, "\\");
+                        pos += 2;
+                    }
+                    s << value;
+                }
+                else {
+                    s << *v;
+                }
+            }
+        }
+        else {
+            count += a->second->getSerializedValues().size();
+        }
+    }
+
+    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));
+}
index d203319..2033627 100644 (file)
@@ -128,8 +128,8 @@ namespace shibsp {
             return m_ids;
         }
         
-        time_t expires() const { return m_expires; }
-        time_t lastAccess() const { return m_lastAccess; }
+        time_t getExpiration() const { return m_expires; }
+        time_t getLastAccess() const { return m_lastAccess; }
         void validate(const Application& application, const char* client_addr, time_t* timeout);
 
     private:
@@ -466,7 +466,7 @@ void RemotedCache::cleanup()
         for (map<string,RemotedSession*>::const_iterator i=m_hashtable.begin(); i!=m_hashtable.end(); ++i) {
             // If the last access was BEFORE the stale timeout...
             i->second->lock();
-            time_t last=i->second->lastAccess();
+            time_t last=i->second->getLastAccess();
             i->second->unlock();
             if (last < stale)
                 stale_keys.push_back(i->first);
index 4d20c95..ffbea17 100644 (file)
@@ -56,7 +56,7 @@ namespace shibsp {
     class StoredSession : public virtual Session
     {
     public:
-        StoredSession(SSCache* cache, DDF& obj) : m_obj(obj), m_nameid(NULL), m_cache(cache) {
+        StoredSession(SSCache* cache, DDF& obj) : m_obj(obj), m_nameid(NULL), m_cache(cache), m_lastAccess(time(NULL)) {
             const char* nameid = obj["nameid"].string();
             if (nameid) {
                 // Parse and bind the document into an XMLObject.
@@ -139,6 +139,19 @@ namespace shibsp {
         const Assertion* getAssertion(const char* id) const;
         void addAssertion(Assertion* assertion);
 
+        time_t getExpiration() const {
+            auto_ptr_XMLCh exp(m_obj["expires"].string());
+            if (exp.get()) {
+                DateTime iso(exp.get());
+                iso.parseDateTime();
+                return iso.getEpoch();
+            }
+            return 0;
+        }
+        time_t getLastAccess() const {
+            return m_lastAccess;
+        }
+
     private:
         void unmarshallAttributes() const;
 
@@ -149,6 +162,7 @@ namespace shibsp {
         mutable vector<const char*> m_ids;
         mutable map<string,Assertion*> m_tokens;
         SSCache* m_cache;
+        time_t m_lastAccess;
     };
     
     class SSCache : public SessionCache, public virtual Remoted
index 20fa6bc..cddba7b 100644 (file)
                                                >\r
                                        </File>\r
                                        <File\r
+                                               RelativePath=".\handler\impl\SessionHandler.cpp"\r
+                                               >\r
+                                       </File>\r
+                                       <File\r
                                                RelativePath=".\handler\impl\SessionInitiator.cpp"\r
                                                >\r
                                        </File>\r
index c0c3eb8..fecc513 100644 (file)
                                                >\r
                                        </File>\r
                                        <File\r
+                                               RelativePath=".\handler\impl\SessionHandler.cpp"\r
+                                               >\r
+                                       </File>\r
+                                       <File\r
                                                RelativePath=".\handler\impl\SessionInitiator.cpp"\r
                                                >\r
                                        </File>\r