virtual Iterator<SAMLAssertion*> getAssertions(Resource& resource);
virtual bool isSessionValid(time_t lifetime, time_t timeout);
virtual const char* getClientAddress() { return m_clientAddress.c_str(); }
+ virtual void release() { cacheitem_lock->unlock(); }
void setCache(InternalCCache *cache) { m_cache = cache; }
time_t lastAccess() { Lock lock(access_lock); return m_lastAccess; }
+ void rdlock() { cacheitem_lock->rdlock(); }
+ void wrlock() { cacheitem_lock->wrlock(); }
private:
ResourceEntry* populate(Resource& resource);
Mutex* access_lock;
RWLock* resource_lock;
+ RWLock* cacheitem_lock;
class ResourceLock
{
const char *client_addr);
virtual void remove(const char* key);
+ InternalCCacheEntry* findi(const char* key);
void cleanup();
+
private:
+ RWLock *lock;
+
SAMLBinding* m_SAMLBinding;
map<string,InternalCCacheEntry*> m_hashtable;
log4cpp::Category* log;
- RWLock *lock;
static void* cleanup_fcn(void*); // XXX Assumed an InternalCCache
bool shutdown;
return NULL;
}
-CCacheEntry* InternalCCache::find(const char* key)
+// assumed a lock is held..
+InternalCCacheEntry* InternalCCache::findi(const char* key)
{
- log->debug("Find: \"%s\"", key);
- ReadLock rwlock(lock);
+ log->debug("FindI: \"%s\"", key);
map<string,InternalCCacheEntry*>::const_iterator i=m_hashtable.find(key);
if (i==m_hashtable.end()) {
return NULL;
}
log->debug("Match Found.");
- return dynamic_cast<CCacheEntry*>(i->second);
+
+ return i->second;
+}
+
+CCacheEntry* InternalCCache::find(const char* key)
+{
+ log->debug("Find: \"%s\"", key);
+ ReadLock rwlock(lock);
+
+ InternalCCacheEntry* entry = findi(key);
+ if (!entry) return NULL;
+
+ // Lock the database for the caller -- they have to release the item.
+ entry->rdlock();
+ return dynamic_cast<CCacheEntry*>(entry);
}
void InternalCCache::insert(const char* key, SAMLAuthenticationStatement *s,
lock->unlock();
}
+// remove the entry from the database and then destroy the cacheentry
void InternalCCache::remove(const char* key)
{
log->debug("removing cache entry \"key\"", key);
- // XXX: FIXME? do we need to delete the CacheEntry?
+ // grab the entry from the database. We'll have a readlock on it.
+ CCacheEntry* entry = findi(key);
+
+ if (!entry)
+ return;
+ // grab the cache write lock
lock->wrlock();
+
+ // verify we've still got the same entry.
+ if (entry != findi(key)) {
+ // Nope -- must've already been removed.
+ lock->unlock();
+ return;
+ }
+
+ // ok, remove the entry.
m_hashtable.erase(key);
lock->unlock();
+
+ // now grab the write lock on the cacheitem.
+ // This will make sure all other threads have released this item.
+ InternalCCacheEntry* ientry = dynamic_cast<InternalCCacheEntry*>(entry);
+ ientry->wrlock();
+
+ // we can release immediately because we know we're not in the database!
+ ientry->release();
+
+ // Now delete the entry
+ delete ientry;
}
void InternalCCache::cleanup()
pop_locks_lock = Mutex::create();
access_lock = Mutex::create();
resource_lock = RWLock::create();
+ cacheitem_lock = RWLock::create();
if (s == NULL) {
log->error("NULL auth statement");
delete i->second;
delete pop_locks_lock;
+ delete cacheitem_lock;
delete resource_lock;
delete access_lock;
}
resource_lock->unlock();
}
+// caller will delete the entry.. don't worry about that here.
void InternalCCacheEntry::remove(const char* resource)
{
log->debug("removing %s", resource);
virtual saml::Iterator<saml::SAMLAssertion*> getAssertions(Resource& resource) = 0;
virtual bool isSessionValid(time_t lifetime, time_t timeout) = 0;
virtual const char* getClientAddress() = 0;
+ virtual void release() = 0;
};
class CCache
virtual ~CCache() = 0;
virtual saml::SAMLBinding* getBinding(const XMLCh* bindingProt) = 0;
- virtual CCacheEntry* find(const char* key) = 0;
+
+ // insert() the Auth Statement into the CCache.
+ //
+ // Make sure you do not hold any open CCacheEntry objects before
+ // you call this method.
+ //
virtual void insert(const char* key, saml::SAMLAuthenticationStatement *s,
const char *client_addr) = 0;
+
+ // find() a CCacheEntry in the CCache for the given key.
+ //
+ // This returns a LOCKED cache entry. You should release() it
+ // when you are done using it.
+ //
+ // Note that you MUST NOT call any other CCache methods while you
+ // are holding this CCacheEntry!
+ //
+ virtual CCacheEntry* find(const char* key) = 0;
+
+ // remove() a key from the CCache
+ //
+ // NOTE: If you previously executed a find(), make sure you
+ // "release()" the CCacheEntry before you try to remove it!
+ //
virtual void remove(const char* key) = 0;
+ // create a CCache instance of the provided type. A NULL type
+ // implies that it should create the default cache type.
+ //
static CCache* getInstance(const char* type);
};
result->status = SHIBRPC_IPADDR_MISMATCH;
result->error_msg =
strdup ("Your IP address does not match the address in the original authentication.");
+ entry->release();
g_shibTargetCCache->remove (argp->cookie.cookie);
return TRUE;
}
log.debug ("Session expired");
result->status = SHIBRPC_SESSION_EXPIRED;
result->error_msg = strdup ("Your session has expired. Re-authenticate.");
+ entry->release();
g_shibTargetCCache->remove (argp->cookie.cookie);
return TRUE;
}
+ entry->release();
+
// ok, we've succeeded..
result->status = SHIBRPC_OK;
result->error_msg = strdup("");
result->status = SHIBRPC_IPADDR_MISMATCH;
result->error_msg =
strdup("Your IP address does not match the address in the original authentication.");
+ entry->release();
return TRUE;
}
os << e;
result->status = SHIBRPC_SAML_EXCEPTION;
result->error_msg = strdup(os.str().c_str());
+ entry->release();
return TRUE;
}
+ entry->release();
+
// and let it fly
result->status = SHIBRPC_OK;
result->error_msg = strdup("");