[cpp-sp] branch main updated: Flesh out admin logout with Hub operation.

Codeberg noreply at shibboleth.net
Wed Oct 21 21:36:51 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/c3910880527e6c1c6516dd0d17e2eabedcc3592c

The following commit(s) were added to refs/heads/main by this push:
     new c3910880 Flesh out admin logout with Hub operation.
c3910880 is described below

commit c3910880527e6c1c6516dd0d17e2eabedcc3592c
Author: Scott Cantor <scott at restingparrotsoftware.com>
AuthorDate: Wed Oct 21 17:36:16 2026 -0400

    Flesh out admin logout with Hub operation.
---
 configs/handlers.ini                       |   1 +
 shibsp/handler/impl/AdminLogoutHandler.cpp | 100 ++++++++++++++++++++++++-----
 shibsp/session/impl/CookieSessionCache.cpp |   3 +-
 3 files changed, 88 insertions(+), 16 deletions(-)

diff --git a/configs/handlers.ini b/configs/handlers.ini
index 4890d6e3..16c355e5 100644
--- a/configs/handlers.ini
+++ b/configs/handlers.ini
@@ -27,6 +27,7 @@ type = AdminLogout
 acl = 127.0.0.1 ::1
 # true suppresses upstream signaling via Hub
 #localOnly = true
+#revocationLifetime = 28800
 
 
 # Legacy SSO/SLO endpoints for SP3 compatibility
diff --git a/shibsp/handler/impl/AdminLogoutHandler.cpp b/shibsp/handler/impl/AdminLogoutHandler.cpp
index 3d8425a7..5ff96b7c 100644
--- a/shibsp/handler/impl/AdminLogoutHandler.cpp
+++ b/shibsp/handler/impl/AdminLogoutHandler.cpp
@@ -24,6 +24,7 @@
 #include "AgentConfig.h"
 #include "handler/SecuredHandler.h"
 #include "logging/Category.h"
+#include "remoting/RemotingService.h"
 #include "session/SessionCache.h"
 
 #include <sstream>
@@ -67,6 +68,9 @@ AdminLogoutHandler::AdminLogoutHandler(const ptree& pt) : AbstractHandler(pt), S
 
 pair<bool,long> AdminLogoutHandler::run(SPRequest& request, bool isHandler) const
 {
+    static const char REVOCATION_LIFETIME_PROP_NAME[] = "revocationLifetime";
+    static unsigned int REVOCATION_LIFETIME_PROP_DEFAULT = 3600 * 8;
+
     // No front-channel notifications, so skip calling logout base class.
 
     // Check ACL in base class.
@@ -83,30 +87,96 @@ pair<bool,long> AdminLogoutHandler::run(SPRequest& request, bool isHandler) cons
 
     const char* applicationId = request.getRequestSettings().first->getString("applicationId", "default");
 
+    // Locate session. Note this may work *even* for client-backed sessions due to in-memory cache.
     unique_lock<Session> session;
     try {
-        session = AgentConfig::getConfig().getAgent().getSessionCache()->find(applicationId, sessionId);
+        session = request.getAgent().getSessionCache()->find(applicationId, sessionId);
     }
-    catch (const std::exception& ex) {
+    catch (const exception& ex) {
         request.error("error locating session: %s", ex.what());
-    }
-
-    // With no session, we return a 404 after "revoking" the session just to be safe.
-    if (!session) {
-        AgentConfig::getConfig().getAgent().getSessionCache()->remove(sessionId);
-        istringstream msg("NOT FOUND");
-        return make_pair(true, request.sendResponse(msg, HTTPResponse::SHIBSP_HTTP_STATUS_NOTFOUND));
+        istringstream msg("ERROR");
+        return make_pair(true, request.sendResponse(msg, HTTPResponse::SHIBSP_HTTP_STATUS_ERROR));
     }
 
     bool localOnly = getBool("localOnly", true);
 
+    // In a local only case, we attempt removal regardless.
     if (localOnly) {
-        session.unlock();
-        AgentConfig::getConfig().getAgent().getSessionCache()->remove(sessionId);
-
-        istringstream msg("OK");
-        return make_pair(true, request.sendResponse(msg, HTTPResponse::SHIBSP_HTTP_STATUS_OK));
+        bool found(session);
+        if (session) {
+            session.unlock();
+        }
+        request.getAgent().getSessionCache()->remove(sessionId);
+        istringstream msg(found ? "OK" : "NOT FOUND");
+        return make_pair(true, request.sendResponse(msg,
+            found ? HTTPResponse::SHIBSP_HTTP_STATUS_OK : HTTPResponse::SHIBSP_HTTP_STATUS_NOTFOUND));
     }
 
-    return make_pair(false, 0L);
+    try {
+        // Before disposing of session, we need to copy out the opaque portion for the Hub.
+        DDF opaqueData;
+        if (session) {
+            opaqueData = session.mutex()->getOpaqueData().copy();
+            session.unlock();
+        }
+
+        // Dispose of the session locally.
+        request.getAgent().getSessionCache()->remove(sessionId);
+
+        // Revoke the session via the Hub.
+        DDF input = request.getAgent().getRemotingService()->build("logout-admin", request);
+        DDFJanitor inputJanitor(input);
+        input.addmember("session.id").string(sessionId);
+        input.getmember("session").add(opaqueData);
+        input.addmember("lifetime").longinteger(
+            getUnsignedInt(REVOCATION_LIFETIME_PROP_NAME, REVOCATION_LIFETIME_PROP_DEFAULT));
+
+        DDF output = request.getAgent().getRemotingService()->send(input);
+        DDFJanitor outputJanitor(output);
+
+        int status;
+        if (output["status"].isint()) {
+            status = output["status"].integer();
+        }
+        else {
+            request.error("absent status from Hub after revoking session (%s)", sessionId);
+            istringstream msg("ERROR");
+            return make_pair(true, request.sendResponse(msg, HTTPResponse::SHIBSP_HTTP_STATUS_ERROR));
+        }
+
+        switch (status) {
+            case 1:
+            {
+                request.info("Hub reported success revoking session (%s)", sessionId);
+                istringstream msg("OK");
+                return make_pair(true, request.sendResponse(msg, HTTPResponse::SHIBSP_HTTP_STATUS_OK));
+            }
+
+            case 0:
+            {
+                request.info("Hub reported partial success revoking session (%s)", sessionId);
+                istringstream msg("PARTIAL");
+                return make_pair(true, request.sendResponse(msg, HTTPResponse::SHIBSP_HTTP_STATUS_OK));
+            }
+
+            case -1:
+            {
+                request.error("Hub reported an error revoking session (%s)", sessionId);
+                istringstream msg("ERROR");
+                return make_pair(true, request.sendResponse(msg, HTTPResponse::SHIBSP_HTTP_STATUS_ERROR));
+            }
+
+            default:
+            {
+                request.error("unexpected status (%d) from Hub revoking session (%s)", status, sessionId);
+                istringstream msg("ERROR");
+                return make_pair(true, request.sendResponse(msg, HTTPResponse::SHIBSP_HTTP_STATUS_ERROR));
+            }
+        }
+    }
+    catch (const exception& e) {
+        request.error("error revoking session (%s) via Hub: %s", sessionId, e.what());
+        istringstream msg("ERROR");
+        return make_pair(true, request.sendResponse(msg, HTTPResponse::SHIBSP_HTTP_STATUS_ERROR));
+    }
 }
diff --git a/shibsp/session/impl/CookieSessionCache.cpp b/shibsp/session/impl/CookieSessionCache.cpp
index 7a2a10ca..4d4f33b9 100644
--- a/shibsp/session/impl/CookieSessionCache.cpp
+++ b/shibsp/session/impl/CookieSessionCache.cpp
@@ -180,7 +180,8 @@ DDF CookieSessionCache::cache_read(
     )
 {
     if (!request) {
-        throw SessionException("Access to request object required to locate cookie-backed session.");
+        log(DEBUG_MARK, "no request available, no access to cookie-backed session store");
+        return DDF();
     }
 
     string encryptedSession = m_chunkedCookieManager->getChunkedCookieValue(*request);

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


More information about the commits mailing list