[cpp-sp] branch main updated: Initial impl of encrypting session files.

Codeberg noreply at shibboleth.net
Tue Sep 22 18:45:40 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/06c5cab9a3a0c76f0a9f1731296de26bea812fff

The following commit(s) were added to refs/heads/main by this push:
     new 06c5cab9 Initial impl of encrypting session files.
06c5cab9 is described below

commit 06c5cab9a3a0c76f0a9f1731296de26bea812fff
Author: Scott Cantor <scott at restingparrotsoftware.com>
AuthorDate: Tue Sep 22 14:45:21 2026 -0400

    Initial impl of encrypting session files.
---
 shibsp/session/impl/AbstractSessionCache.cpp       |   4 +-
 shibsp/session/impl/FilesystemSessionCache.cpp     | 131 +++++++++++++++++----
 shibsp/session/impl/StorageServiceSessionCache.cpp |   1 -
 3 files changed, 106 insertions(+), 30 deletions(-)

diff --git a/shibsp/session/impl/AbstractSessionCache.cpp b/shibsp/session/impl/AbstractSessionCache.cpp
index fbbb358a..f7cbb46b 100644
--- a/shibsp/session/impl/AbstractSessionCache.cpp
+++ b/shibsp/session/impl/AbstractSessionCache.cpp
@@ -644,8 +644,6 @@ bool AbstractSessionCache::update(SPRequest& request, unique_lock<Session>& sess
 {
     // On input we hold an exclusive lock on the relevant session.
 
-    DDF newData;
-
     try {
         // Validate and reformat attribute data.
         const AttributeConfiguration& attrConfig = request.getAgent().getAttributeConfiguration(
@@ -662,7 +660,7 @@ bool AbstractSessionCache::update(SPRequest& request, unique_lock<Session>& sess
 
         // The update requires that we copy the existing DDF from the original session and then
         // replace members with "like" names.
-        newData = dynamic_cast<BasicSession*>(session.mutex())->cloneData();
+        DDF newData = dynamic_cast<BasicSession*>(session.mutex())->cloneData();
         DDFJanitor janitor(newData);
         DDF child = data.first();
         while (!child.isnull()) {
diff --git a/shibsp/session/impl/FilesystemSessionCache.cpp b/shibsp/session/impl/FilesystemSessionCache.cpp
index dd36081d..774b18fd 100644
--- a/shibsp/session/impl/FilesystemSessionCache.cpp
+++ b/shibsp/session/impl/FilesystemSessionCache.cpp
@@ -20,8 +20,10 @@
 
 #include "internal.h"
 #include "exceptions.h"
+#include "Agent.h"
 #include "AgentConfig.h"
 #include "SPRequest.h"
+#include "remoting/RemotingService.h"
 #include "session/AbstractSessionCache.h"
 #include "logging/Category.h"
 #include "util/Date.h"
@@ -79,8 +81,11 @@ namespace {
         static void* file_cleanup_fn(void*);
         static void file_cleanup_callback(const char* pathname, const char* filename, struct stat& stat_buf, void* data);
 
+        void store_session(SPRequest* request, const char* path, DDF& sessionData);
+
         Category& m_spilog;
         string m_dir;
+        bool m_encrypt;
         time_t m_cleanupInterval;
         unsigned int m_fileTimeout;
         condition_variable m_file_cleanup_wait;
@@ -88,11 +93,13 @@ namespace {
     };
 
     static const char CACHE_DIRECTORY_PROP_NAME[] = "cacheDirectory";
+    static const char ENCRYPT_FILES_PROP_NAME[] = "encryptFiles";
     static const char FILE_CLEANUP_TRACKING_FILE_PROP_NAME[] = "fileCleanupTrackingFile";
     static const char FILE_CLEANUP_INTERVAL_PROP_NAME[] = "fileCleanupInterval";
     static const char FILE_TIMEOUT_PROP_NAME[] = "fileTimeout";
 
     static const char CACHE_DIRECTORY_PROP_DEFAULT[] = "sessions";
+    static bool ENCRYPT_FILES_PROP_DEFAULT = false;
     static const char FILE_CLEANUP_TRACKING_FILE_PROP_DEFAULT[] = "shibsp_cache_cleanup";
     static unsigned int FILE_CLEANUP_INTERVAL_PROP_DEFAULT = 1800;
     static unsigned int FILE_TIMEOUT_PROP_DEFAULT = 3600 * 8;
@@ -149,6 +156,8 @@ FilesystemSessionCache::FilesystemSessionCache(const ptree& pt)
         throw ConfigurationException("Configured session cache directory was inaccessible to agent process.");
     }
 
+    m_encrypt = getBool(ENCRYPT_FILES_PROP_NAME, ENCRYPT_FILES_PROP_DEFAULT);
+
     m_cleanupInterval = getUnsignedInt(FILE_CLEANUP_INTERVAL_PROP_NAME, FILE_CLEANUP_INTERVAL_PROP_DEFAULT);
     if (m_cleanupInterval) {
         m_fileTimeout = getUnsignedInt(FILE_TIMEOUT_PROP_NAME, FILE_TIMEOUT_PROP_DEFAULT);
@@ -217,24 +226,24 @@ string FilesystemSessionCache::cache_create(SPRequest* request, const char* cand
 #else
             close(f);
 #endif
-            ofstream os(path);
-            if (!os) {
-                log(ERROR_MARK, "error writing new session to file (%s), errno=%d", path.c_str(), errno);
-                throw IOException("Error writing new session to file.");
-            }
-
-            os << sessionData;
-            if (os) {
+            try {
+                store_session(request, path.c_str(), sessionData);
                 log(DEBUG_MARK, "stored new session (%s)", key.c_str());
                 return key;
             }
+            catch (const exception& e) {
+                log(ERROR_MARK, "exception while storing new session data to file (%s): %s", path.c_str(), e.what());
+                std::remove(path.c_str());
+                throw;
+            }
         }
+
         // If we get here, we're attempting a retry until we exhaust.
         int e = errno;
         if (e != EEXIST) {
-            log(ERROR_MARK, "error opening new session file (%s), errno=%d", path.c_str(), e);
+            log(ERROR_MARK, "error creating new session file (%s), errno=%d", path.c_str(), e);
         } else {
-            log(DEBUG_MARK, "error opening new session file (%s), errno=%d", path.c_str(), e);
+            log(DEBUG_MARK, "error creating new session file (%s), errno=%d", path.c_str(), e);
         }
 
         key = AgentConfig::getConfig().generateRandom(16);
@@ -284,7 +293,7 @@ DDF FilesystemSessionCache::cache_read(
         effective_version++;
     }
 
-    // If we get here, we have the effective variables are set correctly.
+    // If we get here, the effective variables are set correctly.
 
     ifstream is(effective_path);
     if (!is) {
@@ -311,8 +320,32 @@ DDF FilesystemSessionCache::cache_read(
         }
     }
 
-    is >> obj;
-    is.close();
+    if (m_encrypt) {
+        string buf;
+        is >> buf;
+        is.close();
+
+        log(DEBUG_MARK, "decrypting session data");
+        const RemotingService* remoting = AgentConfig::getConfig().getAgent().getRemotingService();
+        DDF in = remoting->build("sealer", nullptr, request ? request->getRequestID() : nullptr);
+        DDFJanitor injanitor(in);
+
+        in.addmember("op").string("D");
+        in.addmember("value").string(buf);
+
+        DDF out = remoting->send(in);   // let this throw to caller
+        DDFJanitor outjanitor(out);
+        const char* decrypted = out["value"].string();
+        if (!decrypted) {
+            throw OperationException("No decrypted session data returned from sealer operation.");
+        }
+        istringstream source(decrypted);
+        source >> obj;
+    }
+    else {
+        is >> obj;
+        is.close();
+    }
 
     if (!isSessionDataValid(obj)) {
         log(ERROR_MARK, "deserialized session from file (%s) was invalid", effective_path.c_str());
@@ -414,7 +447,7 @@ bool FilesystemSessionCache::cache_update(SPRequest* request, const char* key, u
     version++;
     string path = m_dir + key;
     computeVersionedFilename(path, version);
-
+    
     // We attempt an exclusive open to "reserve" the new version's file name.
 #ifdef WIN32
     int f = _open(path.c_str(), _O_CREAT | _O_EXCL, _S_IREAD | _S_IWRITE);
@@ -445,22 +478,21 @@ bool FilesystemSessionCache::cache_update(SPRequest* request, const char* key, u
     close(f);
 #endif
 
-    ofstream os(path);
-    if (!os) {
-        log(ERROR_MARK, "error writing new version of session to file (%s), errno=%d", path.c_str(), errno);
-        throw IOException("Error attempting to open file for writing of updated session.");
-    }
-
     // Ensure the new version is set accurately.
     sessionData.addmember("ver").integer(version);
-    os << sessionData;
-    if (os) {
-        log(DEBUG_MARK, "stored new version of session to file (%s)", path.c_str());
+
+    try {
+        store_session(request, path.c_str(), sessionData);
+        log(DEBUG_MARK, "stored updated session (%s) with version (%u)", key, version);
         return true;
     }
-
-    log(ERROR_MARK, "error writing new version of session to file (%s), errno=%d", path.c_str(), errno);
-    throw IOException("Error attempting to write to file holding updated session version.");
+    catch (const exception& e) {
+        log(ERROR_MARK, "exception while storing updated session to file (%s): %s", path.c_str(), e.what());
+        // Restore old version.
+        sessionData.addmember("ver").integer(--version);
+        std::remove(path.c_str());
+        throw;
+    }
 }
 
 bool FilesystemSessionCache::cache_touch(SPRequest* request, const char* key, unsigned int version, unsigned int timeout)
@@ -535,6 +567,53 @@ void FilesystemSessionCache::cache_remove(SPRequest* request, const char* key)
     }
 }
 
+void FilesystemSessionCache::store_session(SPRequest* request, const char* path, DDF& sessionData)
+{
+    if (m_encrypt) {
+        log(DEBUG_MARK, "encrypting session data");
+        const RemotingService* remoting = AgentConfig::getConfig().getAgent().getRemotingService();
+        DDF in = remoting->build("sealer", nullptr, request ? request->getRequestID() : nullptr);
+        DDFJanitor injanitor(in);
+
+        in.addmember("op").string("E");
+        ostringstream sink;
+        sink << sessionData;
+        in.addmember("value").string(sink.str().c_str());
+
+        DDF out = remoting->send(in);   // let this throw to caller
+        DDFJanitor outjanitor(out);
+        const char* encrypted = out["value"].string();
+        if (!encrypted) {
+            throw OperationException("No encrypted session data returned from sealer operation.");
+        }
+
+        ofstream os(path);
+        if (!os) {
+            log(ERROR_MARK, "error writing new session to file (%s), errno=%d", path, errno);
+            throw IOException("Error opening new session file for writing.");
+        }
+        os << encrypted;
+        if (!os) {
+            log(ERROR_MARK, "error writing new session to file (%s), errno=%d", path, errno);
+            throw IOException("Error writing new session to file.");
+        }
+        os.close();
+    }
+    else {
+        ofstream os(path);
+        if (!os) {
+            log(ERROR_MARK, "error writing new session to file (%s), errno=%d", path, errno);
+            throw IOException("Error opening new session file for writing.");
+        }
+        os << sessionData;
+        if (!os) {
+            log(ERROR_MARK, "error writing new session to file (%s), errno=%d", path, errno);
+            throw IOException("Error writing new session to file.");
+        }
+        os.close();
+    }
+}
+
 void* FilesystemSessionCache::file_cleanup_fn(void* p)
 {
     FilesystemSessionCache* pcache = reinterpret_cast<FilesystemSessionCache*>(p);
diff --git a/shibsp/session/impl/StorageServiceSessionCache.cpp b/shibsp/session/impl/StorageServiceSessionCache.cpp
index 9093f7fd..ed85c98e 100644
--- a/shibsp/session/impl/StorageServiceSessionCache.cpp
+++ b/shibsp/session/impl/StorageServiceSessionCache.cpp
@@ -108,7 +108,6 @@ string StorageServiceSessionCache::cache_create(SPRequest* request, const char*,
         DDFJanitor outJanitor(out);
         const char* key = out["key"].string();
         if (!key || !*key) {
-            log(ERROR_MARK, "no session key returned from create operation");
             throw OperationException("No session key returned from create operation.");
         }
         return string(key);

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


More information about the commits mailing list