[cpp-sp] branch master updated: SSPCPP-775 - Client-side session storage
Scott Cantor
cantor.2 at osu.edu
Thu Feb 22 20:16:05 EST 2018
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch master
in repository cpp-sp.
View the commit online:
http://git.shibboleth.net/view/?p=cpp-sp.git;a=commit;h=328324acf969617e9157aa3ae07d36f808e5a187
The following commit(s) were added to refs/heads/master by this push:
new 328324a SSPCPP-775 - Client-side session storage
328324a is described below
commit 328324acf969617e9157aa3ae07d36f808e5a187
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Feb 22 20:14:39 2018 -0500
SSPCPP-775 - Client-side session storage
https://issues.shibboleth.net/jira/browse/SSPCPP-775
Lightly tested implementation of session save/reload features.
---
shibsp/SessionCache.h | 35 ++--
shibsp/impl/StorageServiceSessionCache.cpp | 266 +++++++++++++++++++++++++++--
shibsp/impl/StorageServiceSessionCache.h | 55 +++---
shibsp/impl/StoredSession.cpp | 12 +-
shibsp/impl/StoredSession.h | 20 +--
5 files changed, 325 insertions(+), 63 deletions(-)
diff --git a/shibsp/SessionCache.h b/shibsp/SessionCache.h
index 5a86b1a..eca14db 100644
--- a/shibsp/SessionCache.h
+++ b/shibsp/SessionCache.h
@@ -66,7 +66,7 @@ namespace shibsp {
* <p>The SessionCache does not itself require locking to manage
* concurrency, but access to each Session is generally exclusive
* or at least controlled, and the caller must unlock a Session
- * to dispose of it.
+ * to dispose of it.</p>
*/
class SHIBSP_API Session : public virtual xmltooling::Lockable
{
@@ -135,7 +135,7 @@ namespace shibsp {
/**
* Returns the NameID associated with a session.
*
- * <p>SAML 1.x identifiers will be promoted to the 2.0 type.
+ * <p>SAML 1.x identifiers will be promoted to the 2.0 type.</p>
*
* @return a SAML 2.0 NameID associated with the session, if any
*/
@@ -152,7 +152,7 @@ namespace shibsp {
/**
* Returns a URI containing an AuthnContextClassRef provided with the session.
*
- * <p>SAML 1.x AuthenticationMethods will be returned as class references.
+ * <p>SAML 1.x AuthenticationMethods will be returned as class references.</p>
*
* @return a URI identifying the authentication context class
*/
@@ -173,7 +173,7 @@ namespace shibsp {
virtual const std::vector<Attribute*>& getAttributes() const=0;
/**
- * Returns the resolved attributes associated with the session, indexed by ID
+ * Returns the resolved attributes associated with the session, indexed by ID.
*
* @return an immutable map of attributes keyed by attribute ID
*/
@@ -182,7 +182,7 @@ namespace shibsp {
/**
* Returns the identifiers of the assertion(s) cached by the session.
*
- * <p>The SSO assertion is guaranteed to be first in the set.
+ * <p>The SSO assertion is guaranteed to be first in the set.</p>
*
* @return an immutable array of AssertionID values
*/
@@ -235,9 +235,9 @@ namespace shibsp {
* Inserts a new session into the cache and binds the session to the outgoing
* client response.
*
- * <p>The newly created session ID is placed into the first parameter.
+ * <p>The newly created session ID is placed into the first parameter.</p>
*
- * <p>The SSO tokens and Attributes remain owned by the caller and are copied by the cache.
+ * <p>The SSO tokens and Attributes remain owned by the caller and are copied by the cache.</p>
*
* @param sessionID reference to string to capture newly inserted session ID
* @param application reference to Application that owns the Session
@@ -334,10 +334,10 @@ namespace shibsp {
* Locates an existing session bound to a request.
*
* <p>If the client address is supplied, then a check will be performed against
- * the address recorded in the record.
+ * the address recorded in the record.</p>
*
* <p>If a bound session is found to have expired, be invalid, etc., and if the request
- * can be used to "clear" the session from subsequent client requests, then it may be cleared.
+ * can be used to "clear" the session from subsequent client requests, then it may be cleared.</p>
*
* @param application reference to Application that owns the Session
* @param request request from client bound to session
@@ -346,7 +346,10 @@ namespace shibsp {
* @return pointer to locked Session, or nullptr
*/
virtual Session* find(
- const Application& application, xmltooling::HTTPRequest& request, const char* client_addr=nullptr, time_t* timeout=nullptr
+ const Application& application,
+ xmltooling::HTTPRequest& request,
+ const char* client_addr=nullptr,
+ time_t* timeout=nullptr
)=0;
/**
@@ -356,21 +359,23 @@ namespace shibsp {
* @param request request from client containing session, or a reference to it
* @param response optional response to client enabling removal of session or reference
*/
- virtual void remove(const Application& application, const xmltooling::HTTPRequest& request, xmltooling::HTTPResponse* response=nullptr)=0;
+ virtual void remove(
+ const Application& application,
+ const xmltooling::HTTPRequest& request,
+ xmltooling::HTTPResponse* response=nullptr
+ )=0;
/**
* Locates an existing session by ID.
*
* <p>If the client address is supplied, then a check will be performed against
- * the address recorded in the record.
+ * the address recorded in the record.</p>
*
* @param application reference to Application that owns the Session
* @param key session key
- * @param client_addr network address of client (if known)
- * @param timeout inactivity timeout to enforce (0 for none, nullptr to bypass check/update of last access)
* @return pointer to locked Session, or nullptr
*/
- virtual Session* find(const Application& application, const char* key, const char* client_addr = nullptr, time_t* timeout = nullptr)=0;
+ virtual Session* find(const Application& application, const char* key)=0;
/**
* Deletes an existing session.
diff --git a/shibsp/impl/StorageServiceSessionCache.cpp b/shibsp/impl/StorageServiceSessionCache.cpp
index 9dce5ba..bb2001d 100644
--- a/shibsp/impl/StorageServiceSessionCache.cpp
+++ b/shibsp/impl/StorageServiceSessionCache.cpp
@@ -48,8 +48,10 @@
#include <boost/bind.hpp>
#include <xmltooling/io/HTTPRequest.h>
#include <xmltooling/io/HTTPResponse.h>
+#include <xmltooling/util/DataSealer.h>
#include <xmltooling/util/NDC.h>
#include <xmltooling/util/Threads.h>
+#include <xmltooling/util/URLEncoder.h>
#include <xmltooling/util/XMLHelper.h>
#include <xercesc/util/XMLUniDefs.hpp>
@@ -59,6 +61,7 @@
# include <saml/saml2/core/Assertions.h>
# include <saml/saml2/metadata/Metadata.h>
# include <xmltooling/XMLToolingConfig.h>
+# include <xmltooling/util/ParserPool.h>
# include <xmltooling/util/StorageService.h>
# include <xercesc/util/XMLStringTokenizer.hpp>
using namespace opensaml::saml2md;
@@ -104,6 +107,7 @@ SSCache::SSCache(const DOMElement* e)
static const XMLCh cacheAssertions[] = UNICODE_LITERAL_15(c,a,c,h,e,A,s,s,e,r,t,i,o,n,s);
static const XMLCh cacheTimeout[] = UNICODE_LITERAL_12(c,a,c,h,e,T,i,m,e,o,u,t);
static const XMLCh excludeReverseIndex[] = UNICODE_LITERAL_19(e,x,c,l,u,d,e,R,e,v,e,r,s,e,I,n,d,e,x);
+ static const XMLCh persistedAttributes[] = UNICODE_LITERAL_19(p,e,r,s,i,s,t,e,d,A,t,t,r,i,b,u,t,e,s);
static const XMLCh inprocTimeout[] = UNICODE_LITERAL_13(i,n,p,r,o,c,T,i,m,e,o,u,t);
static const XMLCh inboundHeader[] = UNICODE_LITERAL_13(i,n,b,o,u,n,d,H,e,a,d,e,r);
static const XMLCh maintainReverseIndex[] = UNICODE_LITERAL_20(m,a,i,n,t,a,i,n,R,e,v,e,r,s,e,I,n,d,e,x);
@@ -162,6 +166,19 @@ SSCache::SSCache(const DOMElement* e)
while (toks.hasMoreTokens())
m_excludedNames.insert(toks.nextToken());
}
+
+ const XMLCh* persistedAttributeIds = e ? e->getAttributeNS(nullptr, persistedAttributes) : nullptr;
+ if (persistedAttributeIds && *persistedAttributeIds) {
+ XMLStringTokenizer toks(persistedAttributeIds);
+ while (toks.hasMoreTokens()) {
+ auto_ptr_char tok(toks.nextToken());
+ m_persistedAttributeIds.insert(tok.get());
+ }
+ }
+
+ if (!m_persistedAttributeIds.empty() && XMLToolingConfig::getConfig().getDataSealer() == nullptr) {
+ throw ConfigurationException("Persisting sessions across nodes requires DataSealer component, check configuration");
+ }
}
#endif
@@ -177,6 +194,7 @@ SSCache::SSCache(const DOMElement* e)
else {
if (listener && conf.isEnabled(SPConfig::OutOfProcess)) {
listener->regListener("find::" STORAGESERVICE_SESSION_CACHE "::SessionCache",this);
+ listener->regListener("recover::" STORAGESERVICE_SESSION_CACHE "::SessionCache", this);
listener->regListener("remove::" STORAGESERVICE_SESSION_CACHE "::SessionCache",this);
listener->regListener("touch::" STORAGESERVICE_SESSION_CACHE "::SessionCache",this);
}
@@ -205,6 +223,7 @@ SSCache::~SSCache()
ListenerService* listener=conf.getServiceProvider()->getListenerService(false);
if (listener && conf.isEnabled(SPConfig::OutOfProcess)) {
listener->unregListener("find::" STORAGESERVICE_SESSION_CACHE "::SessionCache",this);
+ listener->unregListener("recover::" STORAGESERVICE_SESSION_CACHE "::SessionCache", this);
listener->unregListener("remove::" STORAGESERVICE_SESSION_CACHE "::SessionCache",this);
listener->unregListener("touch::" STORAGESERVICE_SESSION_CACHE "::SessionCache",this);
}
@@ -264,6 +283,9 @@ void SSCache::test()
void SSCache::insert(const char* key, time_t expires, const char* name, const char* index, short attempts)
{
+#ifdef _DEBUG
+ xmltooling::NDC ndc("insert");
+#endif
if (attempts > 10) {
throw IOException("Exceeded retry limit.");
}
@@ -517,6 +539,71 @@ void SSCache::insert(
httpResponse.setCookie(shib_cookie.first.c_str(), k.c_str());
sessionID = key.get();
+
+ // See if we need to persist the session data itself to a cookie for cross-node recovery.
+ if (!m_persistedAttributeIds.empty()) {
+ persist(app, httpResponse, obj, expires);
+ }
+}
+
+void SSCache::persist(const Application& app, HTTPResponse& httpResponse, DDF& session, time_t expires) const
+{
+#ifdef _DEBUG
+ xmltooling::NDC ndc("persist");
+#endif
+
+ m_log.debug("checking if session (%s) should be persisted to cookie", session.name());
+
+ // We don't save assertions...
+ session["assertions"].destroy();
+
+ // Check each attribute.
+ DDF attrs = session["attributes"];
+ DDF attr = attrs.first();
+ while (!attr.isnull()) {
+ const char* aname = attr.first().name();
+ if (m_persistedAttributeIds.count(aname) == 0) {
+ m_log.debug("not persisting attribute for session recovery: %s", aname);
+ attr.destroy();
+ }
+ else {
+ m_log.debug("persisting attribute for session recovery: %s", aname);
+ }
+ attr = attrs.next();
+ }
+
+ if (attrs.integer() == 0) {
+ m_log.info("session (%s) contained no attributes requiring persistence, will not be recoverable", session.name());
+ return;
+ }
+
+ ostringstream persisted;
+ persisted << session;
+
+ try {
+ string sealed = XMLToolingConfig::getConfig().getDataSealer()->wrap(persisted.str().c_str(), expires);
+ sealed = XMLToolingConfig::getConfig().getURLEncoder()->encode(sealed.c_str());
+
+ time_t cookieLifetime;
+ pair<string,const char*> shib_cookie = app.getCookieNameProps("_shibsealed_", &cookieLifetime);
+ sealed += shib_cookie.second;
+ if (cookieLifetime > 0) {
+ cookieLifetime += time(nullptr);
+#ifndef HAVE_GMTIME_R
+ struct tm* ptime = gmtime(&cookieLifetime);
+#else
+ struct tm res;
+ struct tm* ptime = gmtime_r(&cookieLifetime, &res);
+#endif
+ char cookietimebuf[64];
+ strftime(cookietimebuf, 64, "; expires=%a, %d %b %Y %H:%M:%S GMT", ptime);
+ sealed += cookietimebuf;
+ }
+ httpResponse.setCookie(shib_cookie.first.c_str(), sealed.c_str());
+ }
+ catch (std::exception& e) {
+ m_log.error("failed to wrap session (%s) with DataSealer: %s", session.name(), e.what());
+ }
}
bool SSCache::matches(
@@ -775,7 +862,7 @@ LogoutEvent* SSCache::newLogoutEvent(const Application& app) const
#endif
-Session* SSCache::find(const Application& app, const char* key, const char* client_addr, time_t* timeout)
+Session* SSCache::_find(const Application& app, const char* key, const char* recovery, const char* client_addr, time_t* timeout)
{
#ifdef _DEBUG
xmltooling::NDC ndc("find");
@@ -806,6 +893,7 @@ Session* SSCache::find(const Application& app, const char* key, const char* clie
DDFJanitor jin(in);
in.structure();
in.addmember("key").string(key);
+ in.addmember("sealed").string(recovery);
in.addmember("application_id").string(app.getId());
if (timeout && *timeout) {
// On 64-bit Windows, time_t doesn't fit in a long, so I'm using ISO timestamps.
@@ -850,8 +938,16 @@ Session* SSCache::find(const Application& app, const char* key, const char* clie
time_t lastAccess = 0;
string record;
int ver = m_storage->readText(key, "session", &record, &lastAccess);
- if (!ver)
- return nullptr;
+ if (!ver) {
+ if (recovery && *recovery && recover(app, key, recovery)) {
+ // Retry the read.
+ ver = m_storage->readText(key, "session", &record, &lastAccess);
+ if (!ver)
+ m_log.warn("recovered session (%s) is missing from storage service", key);
+ }
+ if (!ver)
+ return nullptr;
+ }
if (0 == lastAccess) {
m_log.error("session (ID: %s) did not report time of last access", key);
@@ -952,13 +1048,21 @@ Session* SSCache::find(const Application& app, const char* key, const char* clie
Session* SSCache::find(const Application& app, HTTPRequest& request, const char* client_addr, time_t* timeout)
{
+#ifdef _DEBUG
+ xmltooling::NDC ndc("find");
+#endif
string id = active(app, request);
if (id.empty())
return nullptr;
+
+ pair<string, const char*> shib_cookie = app.getCookieNameProps("_shibsealed_");
+ const char* c = request.getCookie(shib_cookie.first.c_str());
+
try {
- Session* session = find(app, id.c_str(), client_addr, timeout);
+ Session* session = _find(app, id.c_str(), c, client_addr, timeout);
if (session)
return session;
+
HTTPResponse* response = dynamic_cast<HTTPResponse*>(&request);
if (response) {
if (!m_outboundHeader.empty())
@@ -967,6 +1071,8 @@ Session* SSCache::find(const Application& app, HTTPRequest& request, const char*
string exp(shib_cookie.second);
exp += "; expires=Mon, 01 Jan 2001 00:00:00 GMT";
response->setCookie(shib_cookie.first.c_str(), exp.c_str());
+ shib_cookie = app.getCookieNameProps("_shibsealed_");
+ response->setCookie(shib_cookie.first.c_str(), exp.c_str());
}
}
catch (std::exception&) {
@@ -978,14 +1084,124 @@ Session* SSCache::find(const Application& app, HTTPRequest& request, const char*
string exp(shib_cookie.second);
exp += "; expires=Mon, 01 Jan 2001 00:00:00 GMT";
response->setCookie(shib_cookie.first.c_str(), exp.c_str());
+ shib_cookie = app.getCookieNameProps("_shibsealed_");
+ response->setCookie(shib_cookie.first.c_str(), exp.c_str());
}
throw;
}
return nullptr;
}
+bool SSCache::recover(const Application& app, const char* key, const char* data)
+{
+#ifdef _DEBUG
+ xmltooling::NDC ndc("recover");
+#endif
+
+ if (!SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) {
+ m_log.debug("remoting recovery of session from sealed cookie");
+ // Remote the request.
+ DDF in("recover::" STORAGESERVICE_SESSION_CACHE "::SessionCache"), out;
+ DDFJanitor jin(in);
+ in.structure();
+ in.addmember("key").string(key);
+ in.addmember("application_id").string(app.getId());
+ in.addmember("sealed").string(data);
+
+ out = app.getServiceProvider().getListenerService()->send(in);
+ if (!out.isint() || out.integer() != 1) {
+ out.destroy();
+ m_log.debug("recovery of session (%s) failed", key);
+ return false;
+ }
+
+ out.destroy();
+ m_log.debug("session (%s) recovered from sealed cookie", key);
+ }
+ else {
+ // We're out of process, so we can recover the session.
+#ifndef SHIBSP_LITE
+ m_log.debug("attempting recovery of session (%s)", key);
+
+ DDF obj;
+ DDFJanitor jobj(obj);
+ string unwrapped;
+
+ char* dup = nullptr;
+ try {
+ dup = strdup(data);
+ XMLToolingConfig::getConfig().getURLEncoder()->decode(dup);
+ unwrapped = XMLToolingConfig::getConfig().getDataSealer()->unwrap(dup);
+ free(dup);
+
+ stringstream str(unwrapped);
+ str >> obj;
+ }
+ catch (std::exception& e) {
+ if (dup)
+ free(dup);
+ m_log.error("failed to unwrap sealed session data with DataSealer: %s", e.what());
+ return false;
+ }
+
+ if (!obj.isstruct() || !obj.name() || strcmp(obj.name(), key)) {
+ m_log.info("recovered session data was invalid for session (%s)", key);
+ return false;
+ }
+
+ auto_ptr<saml2::NameID> nameidObject;
+ const char* nameid = obj["nameid"].string();
+ if (nameid) {
+ // Parse and bind the document into an XMLObject.
+ istringstream instr(nameid);
+ DOMDocument* doc = XMLToolingConfig::getConfig().getParser().parse(instr);
+ XercesJanitor<DOMDocument> janitor(doc);
+ nameidObject.reset(saml2::NameIDBuilder::buildNameID());
+ nameidObject->unmarshall(doc->getDocumentElement(), true);
+ janitor.release();
+ }
+
+ m_log.debug("storing recovered session (%s)...", key);
+ time_t now = time(nullptr);
+ if (!m_storage->createText(key, "session", unwrapped.c_str(), now + getCacheTimeout(app))) {
+ m_log.debug("recovered session (%s) matched existing record, likely a race condition");
+ return true;
+ }
+
+ // Store the reverse mapping for logout.
+ auto_ptr_char name(nameidObject.get() ? nameidObject->getName() : nullptr);
+ if (name.get() && *name.get() && m_reverseIndex
+ && (m_excludedNames.size() == 0 || m_excludedNames.count(nameidObject->getName()) == 0)) {
+ try {
+ auto_ptr_XMLCh exp(obj["expires"].string());
+ if (exp.get()) {
+ XMLDateTime iso(exp.get());
+ iso.parseDateTime();
+ insert(key, iso.getEpoch(), name.get(), obj["session_index"].string());
+ }
+ }
+ catch (std::exception& ex) {
+ m_log.error("error storing back mapping of NameID for logout: %s", ex.what());
+ }
+ }
+
+ const char* pid = obj["entity_id"].string();
+ const char* prot = obj["protocol"].string();
+ m_log.info("session recovered: ID (%s) IdP (%s) Protocol(%s)",
+ key, pid ? pid : "none", prot ? prot : "none");
+#else
+ throw ConfigurationException("SessionCache recovery requires a DataSealer.");
+#endif
+ }
+
+ return true;
+}
+
void SSCache::remove(const Application& app, const HTTPRequest& request, HTTPResponse* response)
{
+#ifdef _DEBUG
+ xmltooling::NDC ndc("remove");
+#endif
string session_id;
pair<string,const char*> shib_cookie = app.getCookieNameProps("_shibsession_");
@@ -1004,6 +1220,9 @@ void SSCache::remove(const Application& app, const HTTPRequest& request, HTTPRes
string exp(shib_cookie.second);
exp += "; expires=Mon, 01 Jan 2001 00:00:00 GMT";
response->setCookie(shib_cookie.first.c_str(), exp.c_str());
+
+ shib_cookie = app.getCookieNameProps("_shibsealed_");
+ response->setCookie(shib_cookie.first.c_str(), exp.c_str());
}
remove(app, session_id.c_str());
}
@@ -1171,14 +1390,25 @@ void SSCache::receive(DDF& in, ostream& out)
// Do an unversioned read.
string record;
time_t lastAccess = 0;
- if (!m_storage->readText(key, "session", &record, &lastAccess)) {
- m_log.debug("session not found in cache (%s)", key);
- DDF ret(nullptr);
- DDFJanitor jan(ret);
- out << ret;
- return;
+ int ver = m_storage->readText(key, "session", &record, &lastAccess);
+ if (!ver) {
+ const char* recovery = in["sealed"].string();
+ if (recovery && *recovery && recover(*app, key, recovery)) {
+ // Retry the read.
+ ver = m_storage->readText(key, "session", &record, &lastAccess);
+ if (!ver)
+ m_log.warn("recovered session (%s) is missing from storage service", key);
+ }
+
+ if (!ver) {
+ DDF ret(nullptr);
+ DDFJanitor jan(ret);
+ out << ret;
+ return;
+ }
}
- else if (lastAccess == 0) {
+
+ if (lastAccess == 0) {
m_log.error("session (ID: %s) did not report time of last access", key);
throw RetryableProfileException("Your session has expired, and you must re-authenticate.");
}
@@ -1346,6 +1576,20 @@ void SSCache::receive(DDF& in, ostream& out)
DDFJanitor jan(ret);
out << ret;
}
+ else if (!strcmp(in.name(), "recover::" STORAGESERVICE_SESSION_CACHE "::SessionCache")) {
+ const char* key = in["key"].string();
+ const char* cookie = in["sealed"].string();
+ if (!key || !cookie)
+ throw ListenerException("Required parameter missing for session recovery.");
+
+ DDF ret(nullptr);
+ DDFJanitor jan(ret);
+ if (recover(*app, key, cookie))
+ ret.integer(1L);
+ else
+ ret.integer(0L);
+ out << ret;
+ }
}
#endif
diff --git a/shibsp/impl/StorageServiceSessionCache.h b/shibsp/impl/StorageServiceSessionCache.h
index ba68bd0..d2411ba 100644
--- a/shibsp/impl/StorageServiceSessionCache.h
+++ b/shibsp/impl/StorageServiceSessionCache.h
@@ -56,9 +56,9 @@ namespace opensaml {
namespace shibsp {
class StoredSession;
- class SSCache : public shibsp::SessionCache
+ class SSCache : public SessionCache
#ifndef SHIBSP_LITE
- ,public virtual shibsp::Remoted
+ ,public virtual Remoted
#endif
{
public:
@@ -66,11 +66,11 @@ namespace shibsp {
virtual ~SSCache();
#ifndef SHIBSP_LITE
- void receive(shibsp::DDF& in, std::ostream& out);
+ void receive(DDF& in, std::ostream& out);
void insert(
std::string& sessionID,
- const shibsp::Application& app,
+ const Application& app,
const xmltooling::HTTPRequest& httpRequest,
xmltooling::HTTPResponse& httpResponse,
time_t expires,
@@ -82,10 +82,10 @@ namespace shibsp {
const XMLCh* authncontext_class=nullptr,
const XMLCh* authncontext_decl=nullptr,
const std::vector<const opensaml::Assertion*>* tokens=nullptr,
- const std::vector<shibsp::Attribute*>* attributes=nullptr
+ const std::vector<Attribute*>* attributes=nullptr
);
std::vector<std::string>::size_type logout(
- const shibsp::Application& app,
+ const Application& app,
const opensaml::saml2md::EntityDescriptor* issuer,
const opensaml::saml2::NameID& nameid,
const std::set<std::string>* indexes,
@@ -95,41 +95,52 @@ namespace shibsp {
return _logout(app, issuer, nameid, indexes, expires, sessions, 0);
}
bool matches(
- const shibsp::Application& app,
+ const Application& app,
xmltooling::HTTPRequest& request,
const opensaml::saml2md::EntityDescriptor* issuer,
const opensaml::saml2::NameID& nameid,
const std::set<std::string>* indexes
);
#endif
- shibsp::Session* find(const shibsp::Application& app, const char* key, const char* client_addr=nullptr, time_t* timeout=nullptr);
- void remove(const shibsp::Application& app, const char* key);
- void test();
+ std::string active(const Application& app, const xmltooling::HTTPRequest& request);
+ Session* find(const Application& app, xmltooling::HTTPRequest& request, const char* client_addr=nullptr, time_t* timeout=nullptr);
+ void remove(const Application& app, const xmltooling::HTTPRequest& request, xmltooling::HTTPResponse* response=nullptr);
- std::string active(const shibsp::Application& app, const xmltooling::HTTPRequest& request);
- shibsp::Session* find(const shibsp::Application& app, xmltooling::HTTPRequest& request, const char* client_addr = nullptr, time_t* timeout = nullptr);
- void remove(const shibsp::Application& app, const xmltooling::HTTPRequest& request, xmltooling::HTTPResponse* response=nullptr);
+ Session* find(const Application& app, const char* key) {
+ return _find(app, key, nullptr, nullptr, nullptr);
+ }
+ void remove(const Application& app, const char* key);
+ void test();
- unsigned long getCacheTimeout(const shibsp::Application& app) const;
+ unsigned long getCacheTimeout(const Application& app) const;
private:
+ // internal delegates of external methods
+ Session * _find(
+ const Application& app,
+ const char* key,
+ const char* recovery,
+ const char* client_addr,
+ time_t* timeout);
#ifndef SHIBSP_LITE
- // maintain back-mappings of NameID/SessionIndex -> session key
- void insert(const char* key, time_t expires, const char* name, const char* index, short attempts=0);
std::vector<std::string>::size_type _logout(
- const shibsp::Application& app,
+ const Application& app,
const opensaml::saml2md::EntityDescriptor* issuer,
const opensaml::saml2::NameID& nameid,
const std::set<std::string>* indexes,
time_t expires,
std::vector<std::string>& sessions,
short attempts
- );
+ );
+
+ // maintain back-mappings of NameID/SessionIndex -> session key
+ void insert(const char* key, time_t expires, const char* name, const char* index, short attempts=0);
bool stronglyMatches(const XMLCh* idp, const XMLCh* sp, const opensaml::saml2::NameID& n1, const opensaml::saml2::NameID& n2) const;
- shibsp::LogoutEvent* newLogoutEvent(const shibsp::Application& app) const;
+ LogoutEvent* newLogoutEvent(const Application& app) const;
bool m_cacheAssertions,m_reverseIndex;
std::set<xmltooling::xstring> m_excludedNames;
+ std::set<std::string> m_persistedAttributeIds;
#endif
const xercesc::DOMElement* m_root; // Only valid during initialization
unsigned long m_inprocTimeout,m_cacheTimeout,m_cacheAllowance;
@@ -143,6 +154,12 @@ namespace shibsp {
void dormant(const char* key);
static void* cleanup_fn(void*);
+#ifndef SHIBSP_LITE
+ // persistence across nodes
+ void persist(const Application& app, xmltooling::HTTPResponse& httpResponse, DDF& session, time_t expires) const;
+#endif
+ bool recover(const Application& app, const char* key, const char* data);
+
xmltooling::logging::Category& m_log;
bool inproc;
#ifndef SHIBSP_LITE
diff --git a/shibsp/impl/StoredSession.cpp b/shibsp/impl/StoredSession.cpp
index 94fbcf6..d7d9379 100644
--- a/shibsp/impl/StoredSession.cpp
+++ b/shibsp/impl/StoredSession.cpp
@@ -225,14 +225,7 @@ void StoredSession::validate(const Application& app, const char* client_addr, ti
in.addmember("timeout").string(timebuf);
}
- try {
- out=app.getServiceProvider().getListenerService()->send(in);
- }
- catch (...) {
- out.destroy();
- throw;
- }
-
+ out = app.getServiceProvider().getListenerService()->send(in);
if (out.isstruct()) {
// We got an updated record back.
m_cache->m_log.debug("session updated, reconstituting it");
@@ -243,6 +236,9 @@ void StoredSession::validate(const Application& app, const char* client_addr, ti
m_obj.destroy();
m_obj = out;
}
+ else {
+ out.destroy();
+ }
}
else {
#ifndef SHIBSP_LITE
diff --git a/shibsp/impl/StoredSession.h b/shibsp/impl/StoredSession.h
index d5ac966..ae46ff0 100644
--- a/shibsp/impl/StoredSession.h
+++ b/shibsp/impl/StoredSession.h
@@ -52,10 +52,10 @@ namespace shibsp {
class SSCache;
- class StoredSession : public virtual shibsp::Session
+ class StoredSession : public virtual Session
{
public:
- StoredSession(SSCache* cache, shibsp::DDF& obj);
+ StoredSession(SSCache* cache, DDF& obj);
virtual ~StoredSession();
@@ -78,7 +78,7 @@ namespace shibsp {
return nullptr;
}
void setClientAddress(const char* client_addr) {
- shibsp::DDF obj = m_obj["client_addr"];
+ DDF obj = m_obj["client_addr"];
if (!obj.isstruct())
obj = m_obj.addmember("client_addr").structure();
obj.addmember(getAddressFamily(client_addr)).string(client_addr);
@@ -107,19 +107,19 @@ namespace shibsp {
const char* getAuthnContextDeclRef() const {
return m_obj["authncontext_decl"].string();
}
- const std::vector<shibsp::Attribute*>& getAttributes() const {
+ const std::vector<Attribute*>& getAttributes() const {
if (m_attributes.empty())
unmarshallAttributes();
return m_attributes;
}
- const std::multimap<std::string, const shibsp::Attribute*>& getIndexedAttributes() const;
+ const std::multimap<std::string, const Attribute*>& getIndexedAttributes() const;
const std::vector<const char*>& getAssertionIDs() const;
- void validate(const shibsp::Application& application, const char* client_addr, time_t* timeout);
+ void validate(const Application& application, const char* client_addr, time_t* timeout);
#ifndef SHIBSP_LITE
- void addAttributes(const std::vector<shibsp::Attribute*>& attributes);
+ void addAttributes(const std::vector<Attribute*>& attributes);
const opensaml::Assertion* getAssertion(const char* id) const;
void addAssertion(opensaml::Assertion* assertion);
#endif
@@ -134,13 +134,13 @@ namespace shibsp {
private:
void unmarshallAttributes() const;
- shibsp::DDF m_obj;
+ DDF m_obj;
#ifndef SHIBSP_LITE
boost::scoped_ptr<opensaml::saml2::NameID> m_nameid;
mutable std::map< std::string,boost::shared_ptr<opensaml::Assertion> > m_tokens;
#endif
- mutable std::vector<shibsp::Attribute*> m_attributes;
- mutable std::multimap<std::string,const shibsp::Attribute*> m_attributeIndex;
+ mutable std::vector<Attribute*> m_attributes;
+ mutable std::multimap<std::string,const Attribute*> m_attributeIndex;
mutable std::vector<const char*> m_ids;
SSCache* m_cache;
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list