[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