First set of logout base classes and non-building draft of SP-initiated logout.
[shibboleth/sp.git] / shibsp / impl / StorageServiceSessionCache.cpp
index 2d2f0a8..c607c39 100644 (file)
@@ -90,6 +90,9 @@ namespace shibsp {
         const char* getEntityID() const {\r
             return m_obj["entity_id"].string();\r
         }\r
+        const char* getProtocol() const {\r
+            return m_obj["protocol"].string();\r
+        }\r
         const char* getAuthnInstant() const {\r
             return m_obj["authn_instant"].string();\r
         }\r
@@ -150,34 +153,24 @@ namespace shibsp {
             const Application& application,\r
             const char* client_addr=NULL,\r
             const saml2md::EntityDescriptor* issuer=NULL,\r
+            const XMLCh* protocol=NULL,\r
             const saml2::NameID* nameid=NULL,\r
-            const char* authn_instant=NULL,\r
-            const char* session_index=NULL,\r
-            const char* authncontext_class=NULL,\r
-            const char* authncontext_decl=NULL,\r
+            const XMLCh* authn_instant=NULL,\r
+            const XMLCh* session_index=NULL,\r
+            const XMLCh* authncontext_class=NULL,\r
+            const XMLCh* authncontext_decl=NULL,\r
             const vector<const Assertion*>* tokens=NULL,\r
             const multimap<string,Attribute*>* attributes=NULL\r
             );\r
         Session* find(const char* key, const Application& application, const char* client_addr=NULL, time_t* timeout=NULL);\r
         void remove(const char* key, const Application& application);\r
-        void find(\r
-            const saml2md::EntityDescriptor& issuer,\r
-            const saml2::NameID& nameid,\r
-            const char* index,\r
-            const Application& application,\r
-            vector<string>& sessions\r
-            ) {\r
-            byname(issuer, nameid, index, application, sessions, false);\r
-        }\r
         void remove(\r
-            const saml2md::EntityDescriptor& issuer,\r
+            const saml2md::EntityDescriptor* issuer,\r
             const saml2::NameID& nameid,\r
             const char* index,\r
             const Application& application,\r
             vector<string>& sessions\r
-            ) {\r
-            byname(issuer, nameid, index, application, sessions, true);\r
-        }\r
+            );\r
 \r
         Category& m_log;\r
         StorageService* m_storage;\r
@@ -185,14 +178,6 @@ namespace shibsp {
     private:\r
         // maintain back-mappings of NameID/SessionIndex -> session key\r
         void insert(const char* key, time_t expires, const char* name, const char* index);\r
-        void byname(\r
-            const saml2md::EntityDescriptor& issuer,\r
-            const saml2::NameID& nameid,\r
-            const char* index,\r
-            const Application& application,\r
-            vector<string>& sessions,\r
-            bool logout\r
-            );\r
 \r
         bool stronglyMatches(const XMLCh* idp, const XMLCh* sp, const saml2::NameID& n1, const saml2::NameID& n2) const;\r
     };\r
@@ -494,7 +479,7 @@ void SSCache::insert(const char* key, time_t expires, const char* name, const ch
     // Since we can't guarantee uniqueness, check for an existing record.\r
     string record;\r
     time_t recordexp;\r
-    int ver = m_storage->readText("Logout", name, &record, &recordexp);\r
+    int ver = m_storage->readText("NameID", name, &record, &recordexp);\r
     if (ver > 0) {\r
         // Existing record, so we need to unmarshall it.\r
         istringstream in(record);\r
@@ -505,7 +490,7 @@ void SSCache::insert(const char* key, time_t expires, const char* name, const ch
         obj.structure();\r
     }\r
 \r
-    if (!index)\r
+    if (!index || !*index)\r
         index = "_shibnull";\r
     DDF sessions = obj.addmember(index);\r
     if (!sessions.islist())\r
@@ -519,13 +504,13 @@ void SSCache::insert(const char* key, time_t expires, const char* name, const ch
 \r
     // Try and store it back...\r
     if (ver > 0) {\r
-        ver = m_storage->updateText("Logout", name, out.str().c_str(), max(expires, recordexp), ver);\r
+        ver = m_storage->updateText("NameID", name, out.str().c_str(), max(expires, recordexp), ver);\r
         if (ver <= 0) {\r
             // Out of sync, or went missing, so retry.\r
             return insert(key, expires, name, index);\r
         }\r
     }\r
-    else if (!m_storage->createText("Logout", name, out.str().c_str(), expires)) {\r
+    else if (!m_storage->createText("NameID", name, out.str().c_str(), expires)) {\r
         // Hit a dup, so just retry, hopefully hitting the other branch.\r
         return insert(key, expires, name, index);\r
     }\r
@@ -536,11 +521,12 @@ string SSCache::insert(
     const Application& application,\r
     const char* client_addr,\r
     const saml2md::EntityDescriptor* issuer,\r
+    const XMLCh* protocol,\r
     const saml2::NameID* nameid,\r
-    const char* authn_instant,\r
-    const char* session_index,\r
-    const char* authncontext_class,\r
-    const char* authncontext_decl,\r
+    const XMLCh* authn_instant,\r
+    const XMLCh* session_index,\r
+    const XMLCh* authncontext_class,\r
+    const XMLCh* authncontext_decl,\r
     const vector<const Assertion*>* tokens,\r
     const multimap<string,Attribute*>* attributes\r
     )\r
@@ -575,14 +561,25 @@ string SSCache::insert(
         auto_ptr_char entity_id(issuer->getEntityID());\r
         obj.addmember("entity_id").string(entity_id.get());\r
     }\r
-    if (authn_instant)\r
-        obj.addmember("authn_instant").string(authn_instant);\r
+    if (protocol) {\r
+        auto_ptr_char prot(protocol);\r
+        obj.addmember("protocol").string(prot.get());\r
+    }\r
+    if (authn_instant) {\r
+        auto_ptr_char instant(authn_instant);\r
+        obj.addmember("authn_instant").string(instant.get());\r
+    }\r
+    auto_ptr_char index(session_index);\r
     if (session_index)\r
-        obj.addmember("session_index").string(session_index);\r
-    if (authncontext_class)\r
-        obj.addmember("authncontext_class").string(authncontext_class);\r
-    if (authncontext_decl)\r
-        obj.addmember("authncontext_decl").string(authncontext_decl);\r
+        obj.addmember("session_index").string(index.get());\r
+    if (authncontext_class) {\r
+        auto_ptr_char ac(authncontext_class);\r
+        obj.addmember("authncontext_class").string(ac.get());\r
+    }\r
+    if (authncontext_decl) {\r
+        auto_ptr_char ad(authncontext_decl);\r
+        obj.addmember("authncontext_decl").string(ad.get());\r
+    }\r
 \r
     if (nameid) {\r
         ostringstream namestr;\r
@@ -620,7 +617,7 @@ string SSCache::insert(
     auto_ptr_char name(nameid ? nameid->getName() : NULL);\r
     try {\r
         if (name.get())\r
-            insert(key.get(), expires, name.get(), session_index);\r
+            insert(key.get(), expires, name.get(), index.get());\r
     }\r
     catch (exception& ex) {\r
         m_log.error("error storing back mapping of NameID for logout: %s", ex.what());\r
@@ -789,25 +786,24 @@ void SSCache::remove(const char* key, const Application& application)
     xlog->log.info("Destroyed session (applicationId: %s) (ID: %s)", application.getId(), key);\r
 }\r
 \r
-void SSCache::byname(\r
-    const saml2md::EntityDescriptor& issuer,\r
+void SSCache::remove(\r
+    const saml2md::EntityDescriptor* issuer,\r
     const saml2::NameID& nameid,\r
     const char* index,\r
     const Application& application,\r
-    vector<string>& sessionsKilled,\r
-    bool logout\r
+    vector<string>& sessionsKilled\r
     )\r
 {\r
 #ifdef _DEBUG\r
     xmltooling::NDC ndc("remove");\r
 #endif\r
 \r
-    auto_ptr_char entityID(issuer.getEntityID());\r
+    auto_ptr_char entityID(issuer ? issuer->getEntityID() : NULL);\r
     auto_ptr_char name(nameid.getName());\r
 \r
     m_log.info(\r
-        "request to %s sessions from (%s) for (%s) for session index (%s)",\r
-        logout ? "logout" : "locate", entityID.get(), name.get(), index ? index : "all"\r
+        "request to logout sessions from (%s) for (%s) for session index (%s)",\r
+        entityID.get() ? entityID.get() : "unknown", name.get(), index ? index : "all"\r
         );\r
 \r
     if (strlen(name.get()) > 255)\r
@@ -815,7 +811,7 @@ void SSCache::byname(
 \r
     // Read in potentially matching sessions.\r
     string record;\r
-    int ver = m_storage->readText("Logout", name.get(), &record);\r
+    int ver = m_storage->readText("NameID", name.get(), &record);\r
     if (ver == 0) {\r
         m_log.debug("no active sessions to remove for supplied issuer and name identifier");\r
         return;\r
@@ -838,14 +834,12 @@ void SSCache::byname(
                 Locker locker(session);\r
                 if (session) {\r
                     // Same issuer?\r
-                    if (session->getEntityID() && !strcmp(session->getEntityID(), entityID.get())) {\r
+                    if (XMLString::equals(session->getEntityID(), entityID.get())) {\r
                         // Same NameID?\r
-                        if (stronglyMatches(issuer.getEntityID(), application.getXMLString("entityID").second, nameid, *session->getNameID())) {\r
-                            if (logout) {\r
-                                remove(key.string(), application);  // let this throw to detect errors in case the full logout fails?\r
-                                key.destroy();\r
-                            }\r
+                        if (stronglyMatches(issuer->getEntityID(), application.getXMLString("entityID").second, nameid, *session->getNameID())) {\r
                             sessionsKilled.push_back(key.string());\r
+                            remove(key.string(), application);  // let this throw to detect errors in case the full logout fails?\r
+                            key.destroy();\r
                         }\r
                         else {\r
                             m_log.debug("session (%s) contained a non-matching NameID, leaving it alone", key.string());\r
@@ -876,12 +870,12 @@ void SSCache::byname(
     // If possible, write back the mapping record (this isn't crucial).\r
     try {\r
         if (obj.isnull()) {\r
-            m_storage->deleteText("Logout", name.get());\r
+            m_storage->deleteText("NameID", name.get());\r
         }\r
         else if (!sessionsKilled.empty()) {\r
             ostringstream out;\r
             out << obj;\r
-            if (m_storage->updateText("Logout", name.get(), out.str().c_str(), 0, ver) <= 0)\r
+            if (m_storage->updateText("NameID", name.get(), out.str().c_str(), 0, ver) <= 0)\r
                 m_log.warn("logout mapping record changed behind us, leaving it alone");\r
         }\r
     }\r