[cpp-sp] branch main updated: Implement revocation checking in cookie session SPI

Codeberg noreply at shibboleth.net
Thu Oct 29 19:49:39 UTC 2026


This is an automated email from the git hooks/post-receive script.

codeberg pushed a commit to branch main
in repository cpp-sp.

View the commit online:
https://codeberg.org/Shibboleth/cpp-sp/commit/c00f1168f886536c2538f3cad727cfb317d68c7e

The following commit(s) were added to refs/heads/main by this push:
     new c00f1168 Implement revocation checking in cookie session SPI
c00f1168 is described below

commit c00f1168f886536c2538f3cad727cfb317d68c7e
Author: Scott Cantor <scott at restingparrotsoftware.com>
AuthorDate: Thu Oct 29 14:49:22 2026 -0500

    Implement revocation checking in cookie session SPI
---
 shibsp/session/SessionCacheSPI.h                   | 18 +++++--
 shibsp/session/impl/AbstractSessionCache.cpp       |  9 ++--
 shibsp/session/impl/CookieSessionCache.cpp         | 59 ++++++++++++++++++++--
 shibsp/session/impl/FilesystemSessionCache.cpp     | 12 ++++-
 shibsp/session/impl/MemorySessionCache.cpp         | 12 ++++-
 shibsp/session/impl/StorageServiceSessionCache.cpp | 12 ++++-
 tests/session/impl/FilesystemSessionCacheTests.cpp |  1 +
 tests/session/impl/MemorySessionCacheTests.cpp     |  1 +
 8 files changed, 106 insertions(+), 18 deletions(-)

diff --git a/shibsp/session/SessionCacheSPI.h b/shibsp/session/SessionCacheSPI.h
index 2c99a473..b12eac42 100644
--- a/shibsp/session/SessionCacheSPI.h
+++ b/shibsp/session/SessionCacheSPI.h
@@ -115,6 +115,7 @@ namespace shibsp {
          * <p>The return value signals success or a version mismatch/collision.</p>
          * 
          * @param agent request, if available
+         * @param applicationId application ID
          * @param key session key/ID
          * @param version old session version
          * @param sessionData updated session data
@@ -130,14 +131,21 @@ namespace shibsp {
          * <p>This method should return false to indicate that a session has been revoked, removed,
          * or is no longer valid.</p>
          * 
-         * @param request   agent request, if available
-         * @param key       session key/ID
-         * @param version   session version
-         * @param timeout   timeout to enforce if non-zero
+         * @param request       agent request, if available
+         * @param applicationId application ID
+         * @param key           session key/ID
+         * @param version       session version
+         * @param timeout       timeout to enforce if non-zero
          * 
          * @return true iff the session remains valid/available
          */
-        virtual bool cache_touch(SPRequest* request, const char* key, unsigned int version=1, unsigned int timeout=0)=0;
+        virtual bool cache_touch(
+            SPRequest* request,
+            const char* applicationId,
+            const char* key,
+            unsigned int version=1,
+            unsigned int timeout=0
+            )=0;
 
         /**
          * Delete a session record from the underlying storage medium.
diff --git a/shibsp/session/impl/AbstractSessionCache.cpp b/shibsp/session/impl/AbstractSessionCache.cpp
index 50ca33b7..a7a54ba4 100644
--- a/shibsp/session/impl/AbstractSessionCache.cpp
+++ b/shibsp/session/impl/AbstractSessionCache.cpp
@@ -671,7 +671,10 @@ bool AbstractSessionCache::update(SPRequest& request, unique_lock<Session>& sess
         data.destroy();
 
         // Attempt to update the back-end.
-        if (cache_update(&request, session.mutex()->getID(), session.mutex()->getVersion(), newData)) {
+        if (cache_update(&request,
+                session.mutex()->getID(),
+                session.mutex()->getVersion(),
+                newData)) {
             // On success, the version field will have been updated and we need to overwrite the local copy of
             // this session's data.
             dynamic_cast<BasicSession*>(session.mutex())->updateData(newData);
@@ -977,7 +980,7 @@ bool BasicSession::isValid(SPRequest* request, unsigned int lifetime, unsigned i
         if (m_lastAccess - m_lastAccessReported > m_cache.m_storageAccessInterval) {
             try {
                 // Pass a zero to bypass timeout enforcement as we know as well or better than the back-end...
-                if (!m_cache.cache_touch(request, getID(), getVersion(), 0)) {
+                if (!m_cache.cache_touch(request, getApplicationID(), getID(), getVersion(), 0)) {
                     AbstractSessionCache::log(request, m_cache.logger(), Priority::SHIB_WARN,
                         "session (%s) missing in persistent store, invalidating locally", getID());
                     return false;
@@ -995,7 +998,7 @@ bool BasicSession::isValid(SPRequest* request, unsigned int lifetime, unsigned i
         try {
             // The session is locally invalid due to inactivity, but this isn't "truth" because other agent processes may
             // actively be using it.
-            if (!m_cache.cache_touch(request, getID(), getVersion(), timeout)) {
+            if (!m_cache.cache_touch(request, getApplicationID(), getID(), getVersion(), timeout)) {
                 AbstractSessionCache::log(request, m_cache.logger(), Priority::SHIB_WARN,
                     "session (%s) timed out due to inactivity", getID());
                 return false;
diff --git a/shibsp/session/impl/CookieSessionCache.cpp b/shibsp/session/impl/CookieSessionCache.cpp
index 4d4f33b9..8a217c0c 100644
--- a/shibsp/session/impl/CookieSessionCache.cpp
+++ b/shibsp/session/impl/CookieSessionCache.cpp
@@ -57,24 +57,34 @@ namespace {
             const char* client_addr=nullptr
             );
         bool cache_update(SPRequest* request, const char* key, unsigned int version, DDF& data);
-        bool cache_touch(SPRequest* request, const char* key, unsigned int version=1, unsigned int timeout=0);
+        bool cache_touch(
+            SPRequest* request,
+            const char* applicationId,
+            const char* key,
+            unsigned int version=1,
+            unsigned int timeout=0
+            );
         void cache_remove(SPRequest* request, const char* key);
     
     private:
+        bool checkRevocation(const SPRequest& request, const char* applicationId, const char* key);
+
         Category& m_spilog;
         // We store the encrypted timestamp in a separate, unchunked cookie.
         unique_ptr<CookieManager> m_lastUsedCookieManager;
         unique_ptr<CookieManager> m_chunkedCookieManager;
+        bool m_checkRevocation;
     };
 
     static const char CHUNKED_COOKIE_NAME_PROP_NAME[] = "chunkedCookieName";
     static const char CHUNKED_COOKIE_SIZE_PROP_NAME[] = "chunkedCookieSize";
     static const char LAST_USED_COOKIE_NAME_PROP_NAME[] = "lastUsedCookieName";
+    static const char CHECK_REVOCATION_PROP_NAME[] = "checkRevocation";
 
     static const char CHUNKED_COOKIE_NAME_PROP_DEFAULT[] = "__Host-shib_chk";
     static unsigned int CHUNKED_COOKIE_SIZE_PROP_DEFAULT = 3072;
     static const char LAST_USED_COOKIE_NAME_PROP_DEFAULT[] = "__Host-shib_chk_ts";
-    
+    static bool CHECK_REVOCATION_PROP_DEFAULT = false;
 };
 
 // Logging Macros
@@ -93,6 +103,8 @@ namespace shibsp {
 CookieSessionCache::CookieSessionCache(const ptree& pt)
     : AbstractSessionCache(pt), m_spilog(Category::getInstance(SHIBSP_LOGCAT ".SessionCache.StorageService"))
 {
+    m_checkRevocation = getBool(CHECK_REVOCATION_PROP_NAME, CHECK_REVOCATION_PROP_DEFAULT);
+
     // Set up cookie managers.
 
     m_lastUsedCookieManager.reset(new CookieManager(getString(LAST_USED_COOKIE_NAME_PROP_NAME, LAST_USED_COOKIE_NAME_PROP_DEFAULT)));
@@ -169,6 +181,34 @@ string CookieSessionCache::cache_create(SPRequest* request, const char* candidat
     return sessionData.name();
 }
 
+bool CookieSessionCache::checkRevocation(const SPRequest& request, const char* applicationId, const char* key)
+{
+    if (m_checkRevocation) {
+        const RemotingService* remoting = request.getAgent().getRemotingService();
+        try {
+            DDF revoc_in = remoting->build("revocation", applicationId, request.getRequestID());
+            DDFJanitor revoc_janitor(revoc_in);
+            revoc_in.addmember("session.id").string(key);
+
+            DDF revoc_out = remoting->send(revoc_in);
+            int revoc_status = revoc_out.getmember("result").integer();
+            revoc_out.destroy();
+
+            if (revoc_status != 0) {
+                request.warn("session (%s) has been revoked", key);
+                return true;
+            }
+        }
+        catch (const exception& ex) {
+            request.error("error checking revocation of session (%s): %s", key, ex.what());
+            return true;
+        }
+    }
+
+    return false;
+}
+
+
 DDF CookieSessionCache::cache_read(
     SPRequest* request,
     const char* applicationId,
@@ -183,6 +223,10 @@ DDF CookieSessionCache::cache_read(
         log(DEBUG_MARK, "no request available, no access to cookie-backed session store");
         return DDF();
     }
+    
+    if (checkRevocation(*request, applicationId, key)) {
+        return DDF();
+    }
 
     string encryptedSession = m_chunkedCookieManager->getChunkedCookieValue(*request);
     if (encryptedSession.empty()) {
@@ -190,7 +234,8 @@ DDF CookieSessionCache::cache_read(
         return DDF();
     }
 
-    const RemotingService* remoting = AgentConfig::getConfig().getAgent().getRemotingService();
+    const RemotingService* remoting = request->getAgent().getRemotingService();
+
     DDF in = remoting->build("sealer", nullptr, request->getRequestID());
     DDFJanitor injanitor(in);
     DDF decList = in.addmember("decrypt").list();
@@ -449,12 +494,18 @@ bool CookieSessionCache::cache_update(SPRequest* request, const char* key, unsig
     return true;
 }
 
-bool CookieSessionCache::cache_touch(SPRequest* request, const char* key, unsigned int version, unsigned int timeout)
+bool CookieSessionCache::cache_touch(
+    SPRequest* request, const char* applicationId, const char* key, unsigned int version, unsigned int timeout
+    )
 {
     if (!request) {
         throw SessionException("Access to request object required to touch cookie-backed session.");
     }
 
+    if (checkRevocation(*request, applicationId, key)) {
+        return false;
+    }
+
     const RemotingService* remoting = AgentConfig::getConfig().getAgent().getRemotingService();
     DDF in = remoting->build("sealer", nullptr, request->getRequestID());
     DDFJanitor injanitor(in);
diff --git a/shibsp/session/impl/FilesystemSessionCache.cpp b/shibsp/session/impl/FilesystemSessionCache.cpp
index 8ff26bbf..2399c265 100644
--- a/shibsp/session/impl/FilesystemSessionCache.cpp
+++ b/shibsp/session/impl/FilesystemSessionCache.cpp
@@ -74,7 +74,13 @@ namespace {
             const char* client_addr=nullptr
             );
         bool cache_update(SPRequest* request, const char* key, unsigned int version, DDF& data);
-        bool cache_touch(SPRequest* request, const char* key, unsigned int version=1, unsigned int timeout=0);
+        bool cache_touch(
+            SPRequest* request,
+            const char* applicationId,
+            const char* key,
+            unsigned int version=1,
+            unsigned int timeout=0
+            );
         void cache_remove(SPRequest* request, const char* key);
 
     private:
@@ -497,7 +503,9 @@ bool FilesystemSessionCache::cache_update(SPRequest* request, const char* key, u
     }
 }
 
-bool FilesystemSessionCache::cache_touch(SPRequest* request, const char* key, unsigned int version, unsigned int timeout)
+bool FilesystemSessionCache::cache_touch(
+    SPRequest* request, const char* applicationId, const char* key, unsigned int version, unsigned int timeout
+    )
 {
     time_t effective_access = 0;
     string effective_path;
diff --git a/shibsp/session/impl/MemorySessionCache.cpp b/shibsp/session/impl/MemorySessionCache.cpp
index 72d73638..9d8b4184 100644
--- a/shibsp/session/impl/MemorySessionCache.cpp
+++ b/shibsp/session/impl/MemorySessionCache.cpp
@@ -65,7 +65,13 @@ namespace {
             const char* client_addr=nullptr
             );
         bool cache_update(SPRequest* request, const char* key, unsigned int version, DDF& sessionData);
-        bool cache_touch(SPRequest* request, const char* key, unsigned int version=1, unsigned int timeout=0);
+        bool cache_touch(
+            SPRequest* request,
+            const char* applicationId,
+            const char* key,
+            unsigned int version=1,
+            unsigned int timeout=0
+            );
         void cache_remove(SPRequest* request, const char* key);
     
     private:
@@ -280,7 +286,9 @@ bool MemorySessionCache::cache_update(SPRequest* request, const char* key, unsig
     return true;
 }
 
-bool MemorySessionCache::cache_touch(SPRequest* request, const char* key, unsigned int version, unsigned int timeout)
+bool MemorySessionCache::cache_touch(
+    SPRequest* request, const char* applicationId, const char* key, unsigned int version, unsigned int timeout
+    )
 {
     lock_guard<mutex> locker(m_lock);
 
diff --git a/shibsp/session/impl/StorageServiceSessionCache.cpp b/shibsp/session/impl/StorageServiceSessionCache.cpp
index 82bfea79..862a5b56 100644
--- a/shibsp/session/impl/StorageServiceSessionCache.cpp
+++ b/shibsp/session/impl/StorageServiceSessionCache.cpp
@@ -57,7 +57,13 @@ namespace {
             const char* client_addr=nullptr
             );
         bool cache_update(SPRequest* request, const char* key, unsigned int version, DDF& data);
-        bool cache_touch(SPRequest* request, const char* key, unsigned int version=1, unsigned int timeout=0);
+        bool cache_touch(
+            SPRequest* request,
+            const char* applicationId,
+            const char* key,
+            unsigned int version=1,
+            unsigned int timeout=0
+            );
         void cache_remove(SPRequest* request, const char* key);
     
     private:
@@ -301,7 +307,9 @@ bool StorageServiceSessionCache::cache_update(SPRequest* request, const char* ke
     return true;
 }
 
-bool StorageServiceSessionCache::cache_touch(SPRequest* request, const char* key, unsigned int version, unsigned int timeout)
+bool StorageServiceSessionCache::cache_touch(
+    SPRequest* request, const char* applicationId, const char* key, unsigned int version, unsigned int timeout
+    )
 {
     const RemotingService* remoting = AgentConfig::getConfig().getAgent().getRemotingService();
     DDF in = remoting->build("session-cache", nullptr, request ? request->getRequestID() : nullptr);
diff --git a/tests/session/impl/FilesystemSessionCacheTests.cpp b/tests/session/impl/FilesystemSessionCacheTests.cpp
index 0ad22a91..bb6ecaa6 100644
--- a/tests/session/impl/FilesystemSessionCacheTests.cpp
+++ b/tests/session/impl/FilesystemSessionCacheTests.cpp
@@ -86,6 +86,7 @@ struct FilesystemFixture
 
     DDF createTestData(const char* opaque) {
         DDF obj(nullptr);
+        obj.addmember("app_id").string("default");
         obj.addmember("session.opaque").string(opaque);
         DDF attrs = obj.addmember("session.attributes").list();
 
diff --git a/tests/session/impl/MemorySessionCacheTests.cpp b/tests/session/impl/MemorySessionCacheTests.cpp
index fadb4e18..41fa82f5 100644
--- a/tests/session/impl/MemorySessionCacheTests.cpp
+++ b/tests/session/impl/MemorySessionCacheTests.cpp
@@ -51,6 +51,7 @@ struct MemoryFixture
 
     DDF createTestData(const char* opaque) {
         DDF obj(nullptr);
+        obj.addmember("app_id").string("default");
         obj.addmember("session.opaque").string(opaque);
         DDF attrs = obj.addmember("session.attributes").list();
 

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list