[cpp-sp] branch main updated: Implement fuzzy address matching for sessions.

Scott Cantor cantor.2 at osu.edu
Tue Sep 16 20:15:11 UTC 2025


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

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

View the commit online:
http://git.shibboleth.net/view/?p=cpp-sp.git;a=commit;h=cbd25269a0613916d83632ed49a9176777b43c4c

The following commit(s) were added to refs/heads/main by this push:
     new cbd25269 Implement fuzzy address matching for sessions.
cbd25269 is described below

commit cbd25269a0613916d83632ed49a9176777b43c4c
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Tue Sep 16 16:15:02 2025 -0400

    Implement fuzzy address matching for sessions.
---
 shibsp/session/AbstractSessionCache.h          | 30 +++++++++++++++++++-
 shibsp/session/impl/AbstractSessionCache.cpp   | 39 ++++++++++++++++++++++++--
 shibsp/session/impl/FilesystemSessionCache.cpp |  5 ++--
 shibsp/session/impl/MemorySessionCache.cpp     |  5 ++--
 4 files changed, 70 insertions(+), 9 deletions(-)

diff --git a/shibsp/session/AbstractSessionCache.h b/shibsp/session/AbstractSessionCache.h
index b73529ae..4fecf852 100644
--- a/shibsp/session/AbstractSessionCache.h
+++ b/shibsp/session/AbstractSessionCache.h
@@ -28,11 +28,14 @@
 #include <util/BoostPropertySet.h>
 
 #include <condition_variable>
+#include <memory>
 #include <mutex>
 #ifdef HAVE_CXX14
 # include <shared_mutex>
 #endif
 #include <thread>
+#include <vector>
+
 #include <boost/property_tree/ptree_fwd.hpp>
 
 namespace shibsp {
@@ -40,6 +43,7 @@ namespace shibsp {
     class SHIBSP_API AbstractSessionCache;
     class SHIBSP_API Attribute;
     class SHIBSP_API CookieManager;
+    class SHIBSP_API IPRange;
 
 #if defined (_MSC_VER)
     #pragma warning( push )
@@ -137,8 +141,31 @@ namespace shibsp {
             static bool isSessionDataValid(DDF& sessionData);
 
         protected:
-            // Classifies addresses for unique binding to each family.
+            /**
+             * Compares two addresses, allowing for the unreliableNetworks fuzzy match option.
+             * 
+             * @param one   first address
+             * @param two   second address
+             * 
+             * @return true iff the addresses are "equivalent" for session purposes
+             */
+            bool isAddressMatch(const char* one, const char* two) const;
+
+            /**
+             * Returns a string signifying the network address family of the input address.
+             * 
+             * @param addr address to evaluate
+             * 
+             * @return the address family (or a default value, so null is never returned)
+             */
             static const char* getAddressFamily(const std::string& addr);
+
+            /**
+             * Generates version-specific filenames and cookie values by modifying a string in place.
+             * 
+             * @param path base string to append version to
+             * @param version version to append
+             */
             static void computeVersionedFilename(std::string& path, unsigned int version);
 
         private:
@@ -168,6 +195,7 @@ namespace shibsp {
 #endif
             std::map<std::string,std::unique_ptr<BasicSession>> m_hashtable;
             std::unique_ptr<CookieManager> m_cookieManager;
+            std::vector<IPRange> m_unreliableNetworks;
             std::condition_variable m_shutdown_wait;
             std::thread m_cleanup_thread;
             std::string m_issuerAttribute;
diff --git a/shibsp/session/impl/AbstractSessionCache.cpp b/shibsp/session/impl/AbstractSessionCache.cpp
index ab21f06f..5aa2c344 100644
--- a/shibsp/session/impl/AbstractSessionCache.cpp
+++ b/shibsp/session/impl/AbstractSessionCache.cpp
@@ -28,6 +28,8 @@
 #include "logging/Category.h"
 #include "session/AbstractSessionCache.h"
 #include "util/Date.h"
+#include "util/IPRange.h"
+#include "util/Misc.h"
 
 #include <boost/lexical_cast.hpp>
 #include <boost/property_tree/ptree.hpp>
@@ -55,6 +57,7 @@ static const char CLEANUP_INTERVAL_PROP_NAME[] = "cleanupInterval";
 static const char STORAGE_ACCESS_INTERVAL_PROP_NAME[] = "storageAccessInterval";
 static const char INPROC_TIMEOUT_PROP_NAME[] = "inprocTimeout";
 static const char ISSUER_ATTRIBUTE_PROP_NAME[] = "issuerAttribute";
+static const char UNRELIABLE_NETWORKS_PROP_NAME[] = "unreliableNetworks";
 static const char COOKIE_NAME_PROP_NAME[] = "cookieName";
 static const char COOKIE_SECURE_PROP_NAME[] = "cookieSecure";
 static const char COOKIE_HTTPONLY_PROP_NAME[] = "cookieHttpOnly";
@@ -205,6 +208,20 @@ AbstractSessionCache::AbstractSessionCache(const ptree& pt)
     m_cookieManager->setMaxAge(getInt(COOKIE_MAXAGE_PROP_NAME, COOKIE_MAXAGE_PROP_DEFAULT));
     m_cookieManager->setDomain(getString(COOKIE_DOMAIN_PROP_NAME));
     m_cookieManager->setSameSite(getString(COOKIE_SAMESITE_PROP_NAME));
+
+    const char* unreliableNetworks = getString(UNRELIABLE_NETWORKS_PROP_NAME);
+    if (unreliableNetworks) {
+        vector<string> tokenized;
+        split_to_container(tokenized, unreliableNetworks);
+        for (const string& s : tokenized) {
+            try {
+                m_unreliableNetworks.push_back(IPRange::parseCIDRBlock(s.c_str()));
+            }
+            catch (const ConfigurationException& e) {
+                m_log.error("error parsing CIDR expressioon (%s): %s", s.c_str(), e.what());
+            }
+        }
+    }
 }
 
 AbstractSessionCache::~AbstractSessionCache()
@@ -251,6 +268,25 @@ const char* AbstractSessionCache::getAddressFamily(const std::string& addr)
         return "4";
 }
 
+bool AbstractSessionCache::isAddressMatch(const char* one, const char* two) const
+{
+    if (!one || !two) {
+        return false;
+    }
+
+    if (!strcmp(one, two)) {
+        return true;
+    }
+
+    for (const IPRange& cidr : m_unreliableNetworks) {
+        if (cidr.contains(one) && cidr.contains(two)) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
 void AbstractSessionCache::computeVersionedFilename(string& path, unsigned int version)
 {
     try {
@@ -457,8 +493,7 @@ unique_lock<Session> AbstractSessionCache::_find(
             const char* family = AbstractSessionCache::getAddressFamily(client_addr);
             const char* bound_addr = dynamic_cast<BasicSession*>(session.mutex())->getClientAddress(family);
             if (bound_addr) {
-                // TODO: Implement the fuzzy address matching
-                if (strcmp(client_addr, bound_addr)) {
+                if (!isAddressMatch(client_addr, bound_addr)) {
                     m_log.warn("session (%s) access invalid, bound to (%s), accessed from (%s)", key, bound_addr, client_addr);
                     session.unlock();
                 }
diff --git a/shibsp/session/impl/FilesystemSessionCache.cpp b/shibsp/session/impl/FilesystemSessionCache.cpp
index c04a61a0..62135fe2 100644
--- a/shibsp/session/impl/FilesystemSessionCache.cpp
+++ b/shibsp/session/impl/FilesystemSessionCache.cpp
@@ -328,13 +328,12 @@ DDF FilesystemSessionCache::cache_read(
 
     bool updateTimestamp = true;
 
-    // TODO: Implement the fuzzy address matching.
     if (client_addr) {
         const char* family = getAddressFamily(client_addr);
         const char* addr = obj[family].string();
         if (addr) {
-            if (strcmp(client_addr, addr)) {
-                m_spilog.info("session (%s) invalid, bound to address (%s), accessed from (%s)", key, addr, client_addr);
+            if (!isAddressMatch(client_addr, addr)) {
+                m_spilog.info("session (%s) use invalid, bound to address (%s), accessed from (%s)", key, addr, client_addr);
                 return obj.destroy();
             }
         }
diff --git a/shibsp/session/impl/MemorySessionCache.cpp b/shibsp/session/impl/MemorySessionCache.cpp
index 626f23ee..5233aa3f 100644
--- a/shibsp/session/impl/MemorySessionCache.cpp
+++ b/shibsp/session/impl/MemorySessionCache.cpp
@@ -206,13 +206,12 @@ DDF MemorySessionCache::cache_read(
         }
     }
 
-    // TODO: Implement the fuzzy address matching.
     if (client_addr) {
         const char* family = getAddressFamily(client_addr);
         const char* addr = entry->second.first[family].string();
         if (addr) {
-            if (strcmp(client_addr, addr)) {
-                m_spilog.info("session (%s) invalid, bound to address (%s), accessed from (%s)", key, addr, client_addr);
+            if (!isAddressMatch(client_addr, addr)) {
+                m_spilog.info("session (%s) use invalid, bound to address (%s), accessed from (%s)", key, addr, client_addr);
                 m_lock.unlock();
                 return DDF();
             }

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


More information about the commits mailing list