Rework cached data, add (stubbed) statemgr RPC.
authorScott Cantor <cantor.2@osu.edu>
Tue, 22 Mar 2005 06:05:09 +0000 (06:05 +0000)
committerScott Cantor <cantor.2@osu.edu>
Tue, 22 Mar 2005 06:05:09 +0000 (06:05 +0000)
shib-mysql-ccache/shib-mysql-ccache.cpp
shib-target/shib-ccache.cpp
shib-target/shib-target.cpp
shib-target/shib-target.h
shib-target/shibrpc-clnt.c
shib-target/shibrpc-server-stubs.c
shib-target/shibrpc-server.cpp
shib-target/shibrpc-svc.c
shib-target/shibrpc-xdr.c
shib-target/shibrpc.h
shib-target/shibrpc.x

index 27d6248..c1126b4 100644 (file)
@@ -57,9 +57,19 @@ using namespace shibboleth;
 using namespace shibtarget;
 using namespace log4cpp;
 
-#define PLUGIN_VER_MAJOR 1
+#define PLUGIN_VER_MAJOR 2
 #define PLUGIN_VER_MINOR 0
 
+#define STATE_TABLE \
+  "CREATE TABLE state (cookie VARCHAR(64) PRIMARY KEY, " \
+  "application_id VARCHAR(255)," \
+  "atime DATETIME," \
+  "addr VARCHAR(128)," \
+  "profile INT," \
+  "provider VARCHAR(256)," \
+  "statement TEXT," \
+  "response TEXT)" \
+
 static const XMLCh Argument[] =
 { chLatin_A, chLatin_r, chLatin_g, chLatin_u, chLatin_m, chLatin_e, chLatin_n, chLatin_t, chNull };
 static const XMLCh cleanupInterval[] =
@@ -70,6 +80,8 @@ static const XMLCh cacheTimeout[] =
 { chLatin_c, chLatin_a, chLatin_c, chLatin_h, chLatin_e, chLatin_T, chLatin_i, chLatin_m, chLatin_e, chLatin_o, chLatin_u, chLatin_t, chNull };
 static const XMLCh mysqlTimeout[] =
 { chLatin_m, chLatin_y, chLatin_s, chLatin_q, chLatin_l, chLatin_T, chLatin_i, chLatin_m, chLatin_e, chLatin_o, chLatin_u, chLatin_t, chNull };
+static const XMLCh storeAttributes[] =
+{ chLatin_s, chLatin_t, chLatin_o, chLatin_r, chLatin_e, chLatin_A, chLatin_t, chLatin_t, chLatin_r, chLatin_i, chLatin_b, chLatin_u, chLatin_t, chLatin_e, chLatin_s, chNull };
 
 class ShibMySQLCCache;
 class ShibMySQLCCacheEntry : public ISessionCacheEntry
@@ -82,8 +94,10 @@ public:
   virtual void unlock() { m_cacheEntry->unlock(); delete this; }
   virtual bool isValid(time_t lifetime, time_t timeout) const;
   virtual const char* getClientAddress() const { return m_cacheEntry->getClientAddress(); }
+  virtual ShibProfile getProfile() const { return m_cacheEntry->getProfile(); }
+  virtual const char* getProviderId() const { return m_cacheEntry->getProviderId(); }
   virtual const SAMLAuthenticationStatement* getAuthnStatement() const { return m_cacheEntry->getAuthnStatement(); }
-  virtual Iterator<SAMLAssertion*> getAssertions() { return m_cacheEntry->getAssertions(); }
+  virtual const SAMLResponse* getResponse(bool filtered=true) { return m_cacheEntry->getResponse(filtered); }
 
 private:
   bool touch() const;
@@ -105,12 +119,15 @@ public:
   virtual string generateKey() const {return m_cache->generateKey();}
   virtual ISessionCacheEntry* find(const char* key, const IApplication* application);
   virtual void insert(
-        const char* key,
-        const IApplication* application,
-        SAMLAuthenticationStatement *s,
-        const char *client_addr,
-        SAMLResponse* r=NULL,
-        const IRoleDescriptor* source=NULL);
+    const char* key,
+    const IApplication* application,
+    const char* client_addr,
+    ShibProfile profile,
+    const char* providerId,
+    saml::SAMLAuthenticationStatement* s,
+    saml::SAMLResponse* r=NULL,
+    const shibboleth::IRoleDescriptor* source=NULL
+    );
   virtual void remove(const char* key);
 
   void cleanup();
@@ -121,6 +138,7 @@ public:
 private:
   ISessionCache* m_cache;
   ThreadKey* m_mysql;
+  bool m_storeAttributes;
   const DOMElement* m_root; // can only use this during initialization
 
   static void* cleanup_fcn(void*); // XXX Assumed an ShibMySQLCCache
@@ -186,13 +204,13 @@ void ShibMySQLCCache::thread_init()
   if (major != PLUGIN_VER_MAJOR || minor != PLUGIN_VER_MINOR) {
    
     // If we're capable, try upgrading on the fly...
-    if (major == 0 && minor == 0) {
+    if (major == 0  || major == 1) {
        upgradeDatabase(mysql);
     }
     else {
         mysql_close(mysql);
-        log->crit("Invalid database version: %d.%d", major, minor);
-        throw SAMLException("ShibMySQLCCache::thread_init(): Invalid database version");
+        log->crit("Unknown database version: %d.%d", major, minor);
+        throw SAMLException("ShibMySQLCCache::thread_init(): Unknown database version");
     }
   }
 
@@ -200,7 +218,7 @@ void ShibMySQLCCache::thread_init()
   m_mysql->setData(mysql);
 }
 
-ShibMySQLCCache::ShibMySQLCCache(const DOMElement* e)
+ShibMySQLCCache::ShibMySQLCCache(const DOMElement* e) : m_root(e), m_storeAttributes(false)
 {
 #ifdef _DEBUG
   saml::NDC ndc("shibmysql::ShibMySQLCCache");
@@ -209,7 +227,6 @@ ShibMySQLCCache::ShibMySQLCCache(const DOMElement* e)
   m_mysql = ThreadKey::create(&shib_mysql_destroy_handle);
   log = &(Category::getInstance("shibmysql::ShibMySQLCCache"));
 
-  m_root=e;
   initialized = false;
   mysqlInit(e,*log);
   thread_init();
@@ -220,6 +237,11 @@ ShibMySQLCCache::ShibMySQLCCache(const DOMElement* e)
         "edu.internet2.middleware.shibboleth.sp.provider.MemorySessionCacheProvider", e
         )
     );
+    
+  // Load our configuration details...
+  const XMLCh* tag=m_root->getAttributeNS(NULL,storeAttributes);
+  if (tag && *tag && (*tag==chLatin_t || *tag==chDigit_1))
+    m_storeAttributes=true;
 
   // Initialize the cleanup thread
   shutdown_wait = CondWait::create();
@@ -253,7 +275,7 @@ ISessionCacheEntry* ShibMySQLCCache::find(const char* key, const IApplication* a
     log->debug("Looking in database...");
 
     // nothing cached; see if this exists in the database
-    string q = string("SELECT application_id,addr,statement FROM state WHERE cookie='") + key + "' LIMIT 1";
+    string q = string("SELECT application_id,addr,profile,provider,statement,response FROM state WHERE cookie='") + key + "' LIMIT 1";
 
     MYSQL_RES* rows;
     MYSQL* mysql = getMYSQL();
@@ -280,36 +302,59 @@ ISessionCacheEntry* ShibMySQLCCache::find(const char* key, const IApplication* a
     }
 
     log->debug("Match found.  Parsing...");
+    
+    /* Columns in query:
+        0: application_id
+        1: address
+        2: profile
+        3: provider
+        4: statement
+        5: response
+     */
 
     // Pull apart the row and process the results
     MYSQL_ROW row = mysql_fetch_row(rows);
-    IConfig* conf=ShibTargetConfig::getConfig().getINI();
-    Locker locker(conf);
-    const IApplication* application=conf->getApplication(row[0]);
-    if (!application) {
+    if (strcmp(application->getId(),row[0])) {
+        log->crit("An application (%s) attempted to access another application's (%s) session!", application->getId(), row[0]);
         mysql_free_result(rows);
-        throw ShibTargetException(SHIBRPC_INTERNAL_ERROR,"unable to locate application for session, deleted?");
+        return NULL;
     }
-    else if (strcmp(row[0],application->getId())) {
-        log->crit("An application (%s) attempted to access another application's (%s) session!", application->getId(), row[0]);
+
+    Metadata m(application->getMetadataProviders());
+    const IEntityDescriptor* provider=m.lookup(row[3]);
+    if (!provider) {
+        log->crit("no metadata found for identity provider (%s) responsible for the session.", row[3]);
         mysql_free_result(rows);
         return NULL;
     }
 
-    istringstream str(row[2]);
-    SAMLAuthenticationStatement *s = NULL;
+    SAMLAuthenticationStatement* s=NULL;
+    SAMLResponse* r=NULL;
+    const IRoleDescriptor* role=provider->getIDPSSODescriptor(saml::XML::SAML11_PROTOCOL_ENUM);
+    if (!role) {
+        log->crit("no SAML 1.1 IdP role found for identity provider (%s) responsible for the session.", row[3]);
+        mysql_free_result(rows);
+        return NULL;
+    }
 
-    // Try to parse the AuthStatement
+    // Try to parse the SAML data
     try {
-      s = new SAMLAuthenticationStatement(str);
-    } catch (...) {
+        istringstream istr(row[4]);
+        s = new SAMLAuthenticationStatement(istr);
+        if (row[5]) {
+            istr.str(row[5]);
+            r = new SAMLResponse(istr);
+        }
+    }
+    catch (...) {
       mysql_free_result(rows);
       throw;
     }
 
     // Insert it into the memory cache
-    if (s)
-      m_cache->insert(key, application, s, row[1]);
+    if (s) {
+      m_cache->insert(key, application, row[1], static_cast<ShibProfile>(atoi(row[2])), row[3], s, r, role);
+    }
 
     // Free the results, and then re-run the 'find' query
     mysql_free_result(rows);
@@ -324,36 +369,43 @@ ISessionCacheEntry* ShibMySQLCCache::find(const char* key, const IApplication* a
 void ShibMySQLCCache::insert(
     const char* key,
     const IApplication* application,
-    saml::SAMLAuthenticationStatement *s,
-    const char *client_addr,
+    const char* client_addr,
+    ShibProfile profile,
+    const char* providerId,
+    saml::SAMLAuthenticationStatement* s,
     saml::SAMLResponse* r,
-    const IRoleDescriptor* source)
+    const shibboleth::IRoleDescriptor* source
+    )
 {
 #ifdef _DEBUG
   saml::NDC ndc("ShibMySQLCCache::insert");
 #endif
-  ostringstream os;
-  os << *s;
-
-  string q = string("INSERT INTO state VALUES('") + key + "','" + application->getId() + "',NOW(),'" + client_addr + "','" + os.str() + "')";
+  
+  ostringstream q;
+  q << "INSERT INTO state VALUES('" << key << "','" << application->getId() << "',NOW(),'" << client_addr << "'," << profile
+    << ",'" << providerId << "','" << *s << "',";
+  if (m_storeAttributes)
+    q << "'" << *r << "')";
+  else
+    q << "null)";
 
-  log->debug("Query: %s", q.c_str());
+  log->debug("Query: %s", q.str().c_str());
 
   // then add it to the database
   MYSQL* mysql = getMYSQL();
-  if (mysql_query(mysql, q.c_str())) {
+  if (mysql_query(mysql, q.str().c_str())) {
     const char* err=mysql_error(mysql);
     log->error("Error inserting %s: %s", key, err);
     if (isCorrupt(err) && repairTable(mysql,"state")) {
         // Try again...
-        if (mysql_query(mysql, q.c_str()))
+        if (mysql_query(mysql, q.str().c_str()))
           log->error("Error inserting %s: %s", key, mysql_error(mysql));
           throw SAMLException("ShibMySQLCCache::insert(): inset failed");
     }
   }
 
   // Add it to the memory cache
-  m_cache->insert(key, application, s, client_addr, r, source);
+  m_cache->insert(key, application, client_addr, profile, providerId, s, r, source);
 }
 
 void ShibMySQLCCache::remove(const char* key)
@@ -539,9 +591,7 @@ void ShibMySQLCCache::createDatabase(MYSQL* mysql, int major, int minor)
     throw SAMLException("ShibMySQLCCache::createDatabase(): create table cmd failed");
   }
 
-  if (mysql_query(mysql,
-                 "CREATE TABLE state (cookie VARCHAR(64) PRIMARY KEY, application_id VARCHAR(255),"
-                 "atime DATETIME, addr VARCHAR(128), statement TEXT)")) {
+  if (mysql_query(mysql,STATE_TABLE)) {
     log->error ("Error creating state: %s", mysql_error(mysql));
     throw SAMLException("ShibMySQLCCache::createDatabase(): create table cmd failed");
   }
@@ -560,9 +610,7 @@ void ShibMySQLCCache::upgradeDatabase(MYSQL* mysql)
         log->error("Error dropping old session state table: %s", mysql_error(mysql));
     }
 
-    if (mysql_query(mysql,
-        "CREATE TABLE state (cookie VARCHAR(64) PRIMARY KEY, application_id VARCHAR(255),"
-       "atime DATETIME, addr VARCHAR(128), statement TEXT)")) {
+    if (mysql_query(mysql,STATE_TABLE)) {
         log->error ("Error creating state table: %s", mysql_error(mysql));
         throw SAMLException("ShibMySQLCCache::upgradeDatabase(): error creating state table");
     }
index 9623cf6..accf99d 100644 (file)
@@ -117,10 +117,12 @@ class InternalCCacheEntry : public ISessionCacheEntry
 {
 public:
   InternalCCacheEntry(
-    const char* id,
+    const char* key,
     const IApplication* application,
+    const char* client_addr,
+    ShibProfile profile,
+    const char* providerId,
     SAMLAuthenticationStatement* s,
-    const char *client_addr,
     SAMLResponse* r=NULL,
     const IRoleDescriptor* source=NULL
     );
@@ -131,8 +133,10 @@ public:
 
   bool isValid(time_t lifetime, time_t timeout) const;
   const char* getClientAddress() const { return m_clientAddress.c_str(); }
-  const SAMLAuthenticationStatement* getAuthnStatement() const { return p_auth; }
-  Iterator<SAMLAssertion*> getAssertions();
+  ShibProfile getProfile() const { return m_profile; }
+  const char* getProviderId() const { return m_provider_id.c_str(); }
+  const SAMLAuthenticationStatement* getAuthnStatement() const { return m_auth_statement; }
+  const SAMLResponse* getResponse(bool filtered=true);
 
   void setCache(InternalCCache *cache) { m_cache = cache; }
   time_t lastAccess() const { return m_lastAccess; }
@@ -142,22 +146,23 @@ public:
 private:
   void populate();                  // wraps process of checking cache, and repopulating if need be
   bool responseValid();             // checks validity of existing response
-  SAMLResponse* getNewResponse();   // wraps an actual query
+  pair<SAMLResponse*,SAMLResponse*> getNewResponse();   // wraps an actual query
   
   void filter(SAMLResponse* r, const IApplication* application, const IRoleDescriptor* source);
   
   string m_id;
   string m_application_id;
-  string m_originSite;
+  string m_provider_id;
   string m_clientAddress;
   time_t m_sessionCreated;
   time_t m_responseCreated;
   mutable time_t m_lastAccess;
   time_t m_lastRetry;
 
-  const SAMLNameIdentifier* m_nameid;
-  SAMLAuthenticationStatement* p_auth;
-  SAMLResponse* m_response;
+  ShibProfile m_profile;
+  SAMLAuthenticationStatement* m_auth_statement;
+  SAMLResponse* m_response_pre;
+  SAMLResponse* m_response_post;
   InternalCCache *m_cache;
 
   log4cpp::Category* log;
@@ -176,7 +181,14 @@ public:
   string generateKey() const;
   ISessionCacheEntry* find(const char* key, const IApplication* application);
   void insert(
-    const char* key, const IApplication* application, SAMLAuthenticationStatement* s, const char *client_addr, SAMLResponse* r=NULL, const IRoleDescriptor* source=NULL
+    const char* key,
+    const IApplication* application,
+    const char* client_addr,
+    ShibProfile profile,
+    const char* providerId,
+    SAMLAuthenticationStatement* s,
+    SAMLResponse* r=NULL,
+    const IRoleDescriptor* source=NULL
     );
   void remove(const char* key);
 
@@ -190,7 +202,7 @@ private:
 
   log4cpp::Category* log;
 
-  static void* cleanup_fcn(void*); // XXX Assumed an InternalCCache
+  static void* cleanup_fcn(void*); // Assumes an InternalCCache
   bool         shutdown;
   CondWait*    shutdown_wait;
   Thread*      cleanup_thread;
@@ -282,21 +294,19 @@ string InternalCCache::generateKey() const
 // assumes a lock is held..
 InternalCCacheEntry* InternalCCache::findi(const char* key)
 {
-  log->debug("findI: \"%s\"", key);
-
   map<string,InternalCCacheEntry*>::const_iterator i=m_hashtable.find(key);
   if (i==m_hashtable.end()) {
-    log->debug("No Match found");
+    log->debug("No match found");
     return NULL;
   }
-  log->debug("Match Found.");
+  log->debug("Match found");
 
   return i->second;
 }
 
 ISessionCacheEntry* InternalCCache::find(const char* key, const IApplication* application)
 {
-  log->debug("Find: \"%s\"", key);
+  log->debug("searching memory cache for key (%s)", key);
   ReadLock rwlock(lock);
 
   InternalCCacheEntry* entry = findi(key);
@@ -313,12 +323,19 @@ ISessionCacheEntry* InternalCCache::find(const char* key, const IApplication* ap
 }
 
 void InternalCCache::insert(
-    const char* key, const IApplication* application, SAMLAuthenticationStatement* s, const char* client_addr, SAMLResponse* r, const IRoleDescriptor* source
+    const char* key,
+    const IApplication* application,
+    const char* client_addr,
+    ShibProfile profile,
+    const char* providerId,
+    SAMLAuthenticationStatement* s,
+    SAMLResponse* r,
+    const IRoleDescriptor* source
     )
 {
   log->debug("caching new entry for application %s: \"%s\"", application->getId(), key);
 
-  InternalCCacheEntry* entry = new InternalCCacheEntry(key, application, s, client_addr, r, source);
+  InternalCCacheEntry* entry = new InternalCCacheEntry(key, application, client_addr, profile, providerId, s, r, source);
   entry->setCache(this);
 
   lock->wrlock();
@@ -329,7 +346,7 @@ void InternalCCache::insert(
 // remove the entry from the database and then destroy the cacheentry
 void InternalCCache::remove(const char* key)
 {
-  log->debug("removing cache entry \"key\"", key);
+  log->debug("removing cache entry with key (%s)", key);
 
   // lock the cache for writing, which means we know nobody is sitting in find()
   lock->wrlock();
@@ -451,51 +468,49 @@ void* InternalCCache::cleanup_fcn(void* cache_p)
 /******************************************************************************/
 
 InternalCCacheEntry::InternalCCacheEntry(
-    const char* id,
+    const char* key,
     const IApplication* application,
-    SAMLAuthenticationStatement *s,
     const char* client_addr,
+    ShibProfile profile,
+    const char* providerId,
+    SAMLAuthenticationStatement* s,
     SAMLResponse* r,
     const IRoleDescriptor* source
-    ) : m_response(r), m_responseCreated(r ? time(NULL) : 0), m_lastRetry(0),
-        log(&Category::getInstance("shibtarget::InternalCCacheEntry"))
+    ) : m_application_id(application->getId()), m_profile(profile), m_auth_statement(s), m_response_pre(r), m_response_post(NULL),
+        m_responseCreated(r ? time(NULL) : 0), m_lastRetry(0), log(&Category::getInstance("shibtarget::InternalCCacheEntry"))
 {
-  if (!id || !s) {
-    log->error("NULL session ID or auth statement");
-    throw SAMLException("InternalCCacheEntry() passed an empty session ID or SAML Statement");
+  if (!key || !s || !client_addr || !providerId) {
+    log->error("missing required cache entry details");
+    throw SAMLException("InternalCCacheEntry() missing required cache entry details");
   }
 
-  m_id=id;
-  m_application_id=application->getId();
-
-  m_nameid = s->getSubject()->getNameIdentifier();
-  auto_ptr_char d(m_nameid->getNameQualifier());
-  m_originSite = d.get();
-
+  m_id=key;
   m_clientAddress = client_addr;
+  m_provider_id = providerId;
   m_sessionCreated = m_lastAccess = time(NULL);
 
-  // Save for later.
-  p_auth = s;
-  
   // If pushing attributes, filter the response.
-  if (r)
-    filter(r, application, source);
+  if (r) {
+    log->debug("filtering attribute information");
+    m_response_post=static_cast<SAMLResponse*>(r->clone());
+    filter(m_response_post, application, source);
+  }
 
   m_lock = Mutex::create();
 
-  log->info("new session created (ID: %s)", id);
+  log->info("new session created with session ID (%s)", key);
   if (log->isDebugEnabled()) {
-      auto_ptr_char h(m_nameid->getName());
-      log->debug("Handle: \"%s\", Origin: \"%s\", Address: %s", h.get(), d.get(), client_addr);
+      auto_ptr_char h(s->getSubject()->getNameIdentifier()->getName());
+      log->debug("NameID (%s), IdP (%s), Address (%s)", h.get(), providerId, client_addr);
   }
 }
 
 InternalCCacheEntry::~InternalCCacheEntry()
 {
   log->debug("deleting session (ID: %s)", m_id.c_str());
-  delete m_response;
-  delete p_auth;
+  delete m_response_pre;
+  delete m_response_post;
+  delete m_auth_statement;
   delete m_lock;
 }
 
@@ -522,13 +537,13 @@ bool InternalCCacheEntry::isValid(time_t lifetime, time_t timeout) const
   return true;
 }
 
-Iterator<SAMLAssertion*> InternalCCacheEntry::getAssertions()
+const SAMLResponse* InternalCCacheEntry::getResponse(bool filtered)
 {
 #ifdef _DEBUG
   saml::NDC ndc("getAssertions");
 #endif
   populate();
-  return (m_response) ? m_response->getAssertions() : EMPTY(SAMLAssertion*);
+  return filtered ? m_response_post : m_response_pre;
 }
 
 bool InternalCCacheEntry::responseValid()
@@ -540,7 +555,7 @@ bool InternalCCacheEntry::responseValid()
   time_t now=time(NULL) - SAMLConfig::getConfig().clock_skew_secs;
 
   int count = 0;
-  Iterator<SAMLAssertion*> iter = m_response->getAssertions();
+  Iterator<SAMLAssertion*> iter = m_response_pre->getAssertions();
   while (iter.hasNext()) {
     SAMLAssertion* assertion = iter.next();
 
@@ -581,7 +596,7 @@ void InternalCCacheEntry::populate()
   log->debug("populating attributes for session (ID: %s)", m_id.c_str());
 
   // Do we have any data cached?
-  if (m_response) {
+  if (m_response_pre) {
       // Can we use what we have?
       if (responseValid())
         return;
@@ -589,8 +604,9 @@ void InternalCCacheEntry::populate()
       // If we're being strict, dump what we have and reset timestamps.
       if (m_cache->m_strictValidity) {
         log->info("strictly enforcing attribute validity, dumping expired data");
-        delete m_response;
-        m_response=NULL;
+        delete m_response_pre;
+        delete m_response_post;
+        m_response_pre=m_response_post=NULL;
         m_responseCreated=0;
         m_lastRetry=0; 
       }
@@ -605,14 +621,16 @@ void InternalCCacheEntry::populate()
         ") on (applicationId: " <<
             m_application_id <<
         ") for principal from (IdP: " <<
-            m_originSite <<
+            m_provider_id <<
         ")";
     stc.releaseTransactionLog();
 
-    SAMLResponse* new_response=getNewResponse();
-    if (new_response) {
-        delete m_response;
-        m_response=new_response;
+    pair<SAMLResponse*,SAMLResponse*> new_responses=getNewResponse();
+    if (new_responses.first) {
+        delete m_response_pre;
+        delete m_response_post;
+        m_response_pre=new_responses.first;
+        m_response_post=new_responses.second;
         m_responseCreated=time(NULL);
         m_lastRetry=0;
         log->debug("fetched and stored new response");
@@ -632,7 +650,7 @@ void InternalCCacheEntry::populate()
   }
 }
 
-SAMLResponse* InternalCCacheEntry::getNewResponse()
+pair<SAMLResponse*,SAMLResponse*> InternalCCacheEntry::getNewResponse()
 {
 #ifdef _DEBUG
     saml::NDC ndc("getNewResponse");
@@ -641,7 +659,7 @@ SAMLResponse* InternalCCacheEntry::getNewResponse()
     // The retryInterval determines how often to poll an AA that might be down.
     time_t now=time(NULL);
     if ((now - m_lastRetry) < m_cache->m_retryInterval)
-        return NULL;
+        return pair<SAMLResponse*,SAMLResponse*>(NULL,NULL);
     if (m_lastRetry)
         log->debug("retry interval exceeded, so trying again");
     m_lastRetry=now;
@@ -664,7 +682,7 @@ SAMLResponse* InternalCCacheEntry::getNewResponse()
 
     // Try this request.
     Metadata m(application->getMetadataProviders());
-    const IEntityDescriptor* site=m.lookup(m_nameid->getNameQualifier());
+    const IEntityDescriptor* site=m.lookup(m_provider_id.c_str());
     if (!site) {
         log->error("unable to locate identity provider's metadata during attribute query");
         throw ShibTargetException(SHIBRPC_INTERNAL_ERROR,"Unable to locate identity provider's metadata during attribute query.");
@@ -686,7 +704,7 @@ SAMLResponse* InternalCCacheEntry::getNewResponse()
     try {
         // Build a SAML Request....
         SAMLAttributeQuery* q=new SAMLAttributeQuery(
-            new SAMLSubject(static_cast<SAMLNameIdentifier*>(m_nameid->clone())),
+            new SAMLSubject(static_cast<SAMLNameIdentifier*>(m_auth_statement->getSubject()->getNameIdentifier()->clone())),
             providerID.second,
             application->getAttributeDesignators().clone()
             );
@@ -737,14 +755,17 @@ SAMLResponse* InternalCCacheEntry::getNewResponse()
             }
         }
 
-        if (signedResponse.first && signedResponse.second && !response->isSigned()) {
+        if (response && signedResponse.first && signedResponse.second && !response->isSigned()) {
             delete response;
             response=NULL;
             log->error("unsigned response obtained, but we were told it must be signed.");
         }
-        else {
-            // Run it through the filter. Note that we could end up with an empty response.
-            filter(response,application,AA);
+        
+        if (response) {
+            // Run a copy through the filter. Note that we could end up with an empty response.
+            SAMLResponse* copy = static_cast<SAMLResponse*>(response->clone());
+            filter(copy,application,AA);
+            return make_pair(response,copy);
         }
     }
     catch (SAMLException& e) {
@@ -756,12 +777,8 @@ SAMLResponse* InternalCCacheEntry::getNewResponse()
         throw ShibTargetException(SHIBRPC_SAML_EXCEPTION, os.str().c_str(), AA);
     }
     
-    // See if we got a response.
-    if (!response) {
-        log->error("no response obtained");
-        throw ShibTargetException(SHIBRPC_INTERNAL_ERROR,"Unable to obtain attributes from user's identity provider.",AA);
-    }
-    return response;
+    log->error("no response obtained");
+    throw ShibTargetException(SHIBRPC_INTERNAL_ERROR,"Unable to obtain attributes from user's identity provider.",AA);
 }
 
 void InternalCCacheEntry::filter(SAMLResponse* r, const IApplication* application, const IRoleDescriptor* source)
@@ -771,6 +788,7 @@ void InternalCCacheEntry::filter(SAMLResponse* r, const IApplication* applicatio
     Trust t(application->getTrustProviders());
 
     // Examine each new assertion...
+    r->toDOM();
     Iterator<SAMLAssertion*> assertions=r->getAssertions();
     for (unsigned long i=0; i < assertions.size();) {
         try {
index 94d5f67..0246863 100644 (file)
@@ -120,8 +120,11 @@ namespace shibtarget {
     const char *session_id;
     string m_cookies;
 
-    vector<SAMLAssertion*> m_assertions;
+    ShibProfile m_sso_profile;
+    string m_provider_id;
     SAMLAuthenticationStatement* m_sso_statement;
+    SAMLResponse* m_pre_response;
+    SAMLResponse* m_post_response;
     
     // These are the actual request parameters set via the init method.
     string m_url;
@@ -164,7 +167,9 @@ void ShibTarget::init(ShibTargetConfig *config,
                      string uri, string content_type, string remote_host,
                      string method)
 {
+#ifdef _DEBUG
   saml::NDC ndc("ShibTarget::init");
+#endif
 
   if (m_priv->m_app)
     throw runtime_error("ShibTarget Already Initialized");
@@ -233,18 +238,26 @@ ShibTarget::doCheckAuthN(bool requireSessionFlag, bool handleProfile)
     }
 
     procState = "Session Processing Error";
-    RPCError *status = sessionGet(session_id, m_priv->m_remote_addr.c_str(), m_priv->m_assertions, &m_priv->m_sso_statement);
+    RPCError* status = sessionGet(
+        session_id,
+        m_priv->m_remote_addr.c_str(),
+        m_priv->m_sso_profile,
+        m_priv->m_provider_id,
+        &m_priv->m_sso_statement,
+        &m_priv->m_pre_response,
+        &m_priv->m_post_response
+        );
 
     if (status->isError()) {
 
       // If no session is required, bail now.
       if (!requireSession.second)
         return pair<bool,void*>(true, returnOK());
-                          // XXX: Or should this be DECLINED?
-                          // Has to be OK because DECLINED will just cause Apache
-                          // to fail when it can't locate anything to process the
-                          // AuthType.  No session plus requireSession false means
-                          // do not authenticate the user at this time.
+                   // XXX: Or should this be DECLINED?
+                   // Has to be OK because DECLINED will just cause Apache
+                   // to fail when it can't locate anything to process the
+                   // AuthType.  No session plus requireSession false means
+                   // do not authenticate the user at this time.
       else if (status->isRetryable()) {
         // Session is invalid but we can retry the auth -- generate an AuthnRequest
         delete status;
@@ -347,8 +360,16 @@ ShibTarget::doHandleProfile(void)
     }
        
     // process the submission
-    string cookie,target;
-    RPCError* status = sessionNew(cgistr.c_str(), m_priv->m_remote_addr.c_str(),cookie,target);
+    string cookie,target,statemgr_packet;
+    RPCError* status = sessionNew(
+        SAML_11_POST | SAML_11_ARTIFACT,
+        cgistr.c_str(),
+        NULL,   // XXX: no state token yet
+        m_priv->m_remote_addr.c_str(),
+        cookie,
+        target,
+        statemgr_packet
+        );
 
     if (status->isError()) {
       char buf[25];
@@ -421,7 +442,7 @@ ShibTarget::doCheckAuthZ(void)
     if (m_priv->m_settings.second) {
       Locker acllock(m_priv->m_settings.second);
       if (!m_priv->m_settings.second->authorized(*m_priv->m_sso_statement,
-                                                m_priv->m_assertions)) {
+            m_priv->m_post_response ? m_priv->m_post_response->getAssertions() : EMPTY(SAMLAssertion*))) {
         log(LogLevelError, "doCheckAuthZ: access control provider denied access");
         goto out;
       }
@@ -650,7 +671,9 @@ ShibTarget::doCheckAuthZ(void)
 pair<bool,void*>
 ShibTarget::doExportAssertions(bool exportAssertion)
 {
+#ifdef _DEBUG
   saml::NDC ndc("ShibTarget::doExportAssertions");
+#endif
 
   ShibMLP mlp;
   const char *procState = "Attribute Processing Error";
@@ -667,9 +690,17 @@ ShibTarget::doExportAssertions(bool exportAssertion)
     if (!m_priv->m_sso_statement) {
         // No data yet, so we need to get the session. This can only happen
         // if the call to doCheckAuthn doesn't happen in the same object lifetime.
-        RPCError* status = sessionGet(session_id, m_priv->m_remote_addr.c_str(), m_priv->m_assertions, &m_priv->m_sso_statement);
+        RPCError* status = sessionGet(
+            session_id,
+            m_priv->m_remote_addr.c_str(),
+            m_priv->m_sso_profile,
+            m_priv->m_provider_id,
+            &m_priv->m_sso_statement,
+            &m_priv->m_pre_response,
+            &m_priv->m_post_response
+            );
         if (status->isError()) {
-            string er = "getAssertions failed: ";
+            string er = "sessionGet failed: ";
             er += status->getText();
             log(ShibTarget::LogLevelError, er);
             mlp.insert(*status);
@@ -700,15 +731,14 @@ ShibTarget::doExportAssertions(bool exportAssertion)
     if (!exp.first || !exp.second)
       if (exportAssertion)
         exp.second=true;
-    if (exp.second && m_priv->m_assertions.size()) {
+    if (exp.second && m_priv->m_pre_response) {
       ostringstream os;
-      os << *(m_priv->m_assertions[0]);
+      os << *(m_priv->m_pre_response);
       unsigned int outlen;
-      char* assn = (char*)os.str().c_str();
-      XMLByte* serialized = Base64::encode(reinterpret_cast<XMLByte*>(assn), os.str().length(), &outlen);
-      string assertion = (char*)serialized;
-      XMLString::release(&serialized);      
-      setHeader("Shib-Attributes", assertion.c_str());
+      char* resp = (char*)os.str().c_str();
+      XMLByte* serialized = Base64::encode(reinterpret_cast<XMLByte*>(resp), os.str().length(), &outlen);
+      setHeader("Shib-Attributes", reinterpret_cast<char*>(serialized));
+      XMLString::release(&serialized);
     }
 
     // Export the SAML AuthnMethod and the origin site name, and possibly the NameIdentifier.
@@ -716,10 +746,9 @@ ShibTarget::doExportAssertions(bool exportAssertion)
     clearHeader("Shib-Identity-Provider");
     clearHeader("Shib-Authentication-Method");
     clearHeader("Shib-NameIdentifier-Format");
-    auto_ptr_char os(m_priv->m_sso_statement->getSubject()->getNameIdentifier()->getNameQualifier());
+    setHeader("Shib-Origin-Site", m_priv->m_provider_id.c_str());
+    setHeader("Shib-Identity-Provider", m_priv->m_provider_id.c_str());
     auto_ptr_char am(m_priv->m_sso_statement->getAuthMethod());
-    setHeader("Shib-Origin-Site", os.get());
-    setHeader("Shib-Identity-Provider", os.get());
     setHeader("Shib-Authentication-Method", am.get());
     
     // Export NameID?
@@ -743,7 +772,7 @@ ShibTarget::doExportAssertions(bool exportAssertion)
     setHeader("Shib-Application-ID", m_priv->m_app->getId());
 
     // Export the attributes.
-    Iterator<SAMLAssertion*> a_iter(m_priv->m_assertions);
+    Iterator<SAMLAssertion*> a_iter(m_priv->m_post_response ? m_priv->m_post_response->getAssertions() : EMPTY(SAMLAssertion*));
     while (a_iter.hasNext()) {
       SAMLAssertion* assert=a_iter.next();
       Iterator<SAMLStatement*> statements=assert->getStatements();
@@ -967,43 +996,52 @@ ShibTarget::getLazyAuthnRequest(const char* query_string) const
     return getAuthnRequest(target);
 }
         
-RPCError* 
-ShibTarget::sessionNew(const char* packet, const char* ip, string& cookie, string& target)
-  const
+RPCError* ShibTarget::sessionNew(
+    int supported_profiles,
+    const char* packet,
+    const char* statemgr_cookie,
+    const char* ip,
+    string& cookie,
+    string& target,
+    string& statemgr_packet
+    ) const
 {
 #ifdef _DEBUG
-  saml::NDC ndc("sessionCreate");
+  saml::NDC ndc("sessionNew");
 #endif
   Category& log = Category::getInstance("shibtarget.ShibTarget");
 
   if (!packet || !*packet) {
-    log.error ("Empty SAML response content");
-    return new RPCError(SHIBRPC_RESPONSE_MISSING,  "Empty SAML response content");
+    log.error("Empty profile content");
+    return new RPCError(SHIBRPC_RESPONSE_MISSING, "Empty profile content");
   }
 
   if (!ip || !*ip) {
-    log.error ("Invalid IP address");
+    log.error("Invalid IP address");
     return new RPCError(SHIBRPC_IPADDR_MISSING, "Invalid IP address");
   }
   
+  if (supported_profiles <= 0) {
+    log.error("No profile support indicated");
+    return new RPCError(SHIBRPC_INTERNAL_ERROR, "No profile support indicated");
+  }
+  
   shibrpc_new_session_args_2 arg;
   arg.recipient = (char*) m_priv->m_shireURL.c_str();
   arg.application_id = (char*) m_priv->m_app->getId();
   arg.packet = (char*)packet;
   arg.client_addr = (char*)ip;
-  arg.checkIPAddress = true;
-
-  log.info ("create session for user at %s for application %s", ip, arg.application_id);
+  arg.supported_profiles = supported_profiles;
+  if (statemgr_cookie)
+    arg.cookie = (char*)statemgr_cookie;
+  else
+    arg.cookie = "";
 
-  const IPropertySet* props=m_priv->m_app->getPropertySet("Sessions");
-  if (props) {
-      pair<bool,bool> pcheck=props->getBool("checkAddress");
-      if (pcheck.first)
-          arg.checkIPAddress = pcheck.second;
-  }
+  log.info("create session for user at (%s) for application (%s) with state token (%s)",
+    ip, arg.application_id, statemgr_cookie);
 
   shibrpc_new_session_ret_2 ret;
-  memset (&ret, 0, sizeof(ret));
+  memset(&ret, 0, sizeof(ret));
 
   // Loop on the RPC in case we lost contact the first time through
   int retry = 1;
@@ -1033,10 +1071,12 @@ ShibTarget::sessionNew(const char* packet, const char* ip, string& cookie, strin
   if (ret.status.status)
     retval = new RPCError(&ret.status);
   else {
-    log.debug ("new cookie: %s", ret.cookie);
+    log.debug ("new session cookie: %s", ret.cookie);
     cookie = ret.cookie;
     if (ret.target)
         target = ret.target;
+    if (ret.packet)
+        statemgr_packet = ret.packet;
     retval = new RPCError();
   }
 
@@ -1047,12 +1087,14 @@ ShibTarget::sessionNew(const char* packet, const char* ip, string& cookie, strin
   return retval;
 }
 
-RPCError*
-ShibTarget::sessionGet(
+RPCError* ShibTarget::sessionGet(
     const char* cookie,
     const char* ip,
-    std::vector<saml::SAMLAssertion*>& assertions,
-    saml::SAMLAuthenticationStatement **statement
+    ShibProfile& profile,
+    string& provider_id,
+    SAMLAuthenticationStatement** auth_statement,
+    SAMLResponse** attr_response_pre,
+    SAMLResponse** attr_response_post
     ) const
 {
 #ifdef _DEBUG
@@ -1061,45 +1103,28 @@ ShibTarget::sessionGet(
   Category& log = Category::getInstance("shibtarget.ShibTarget");
 
   if (!cookie || !*cookie) {
-    log.error ("No cookie value was provided");
+    log.error("No cookie value was provided");
     return new RPCError(SHIBRPC_NO_SESSION, "No cookie value was provided");
   }
   else if (strchr(cookie,'=')) {
-    log.error ("The cookie value wasn't extracted successfully, use a more unique cookie name for your installation.");
+    log.error("The cookie value wasn't extracted successfully, use a more unique cookie name for your installation.");
     return new RPCError(SHIBRPC_INTERNAL_ERROR, "The cookie value wasn't extracted successfully, use a more unique cookie name for your installation.");
   }
 
   if (!ip || !*ip) {
-    log.error ("Invalid IP Address");
+    log.error("Invalid IP Address");
     return new RPCError(SHIBRPC_IPADDR_MISSING, "Invalid IP Address");
   }
 
-  log.info ("get session for client address (%s)", ip);
-  log.debug ("session cookie (%s)", cookie);
+  log.info("getting session for client at (%s)", ip);
+  log.debug("session cookie (%s)", cookie);
 
   shibrpc_get_session_args_2 arg;
 
   arg.cookie = (char*)cookie;
   arg.client_addr = (char*)ip;
   arg.application_id = (char*)m_priv->m_app->getId();
-  
-  // Get rest of input from the application Session properties.
-  arg.lifetime = 3600;
-  arg.timeout = 1800;
-  arg.checkIPAddress = true;
-  const IPropertySet* props=m_priv->m_app->getPropertySet("Sessions");
-  if (props) {
-      pair<bool,unsigned int> p=props->getUnsignedInt("lifetime");
-      if (p.first)
-          arg.lifetime = p.second;
-      p=props->getUnsignedInt("timeout");
-      if (p.first)
-          arg.timeout = p.second;
-      pair<bool,bool> pcheck=props->getBool("checkAddress");
-      if (pcheck.first)
-          arg.checkIPAddress = pcheck.second;
-  }
-  
+
   shibrpc_get_session_ret_2 ret;
   memset (&ret, 0, sizeof(ret));
 
@@ -1133,25 +1158,34 @@ ShibTarget::sessionGet(
   else {
     try {
       try {
-        for (u_int i = 0; i < ret.assertions.assertions_len; i++) {
-          istringstream attrstream(ret.assertions.assertions_val[i].xml_string);
-          SAMLAssertion *as = NULL;
-          log.debugStream() << "Trying to decode assertion " << i << ": " <<
-                ret.assertions.assertions_val[i].xml_string << CategoryStream::ENDLINE;
-          assertions.push_back(new SAMLAssertion(attrstream));
+        profile = ret.profile;
+        provider_id = ret.provider_id;
+        
+        // return the Authentication Statement
+        if (auth_statement) {
+          istringstream authstream(ret.auth_statement);
+          
+          log.debugStream() << "Trying to decode authentication statement: "
+                << ret.auth_statement << CategoryStream::ENDLINE;
+          *auth_statement = new SAMLAuthenticationStatement(authstream);
         }
 
-        // return the Authentication Statement
-        if (statement) {
-          istringstream authstream(ret.auth_statement.xml_string);
-          SAMLAuthenticationStatement *auth = NULL;
+        // return the unfiltered Response
+        if (attr_response_pre) {
+          istringstream prestream(ret.attr_response_pre);
           
-          log.debugStream() << "Trying to decode authentication statement: " <<
-                ret.auth_statement.xml_string << CategoryStream::ENDLINE;
-            auth = new SAMLAuthenticationStatement(authstream);
-        
-            // Save off the statement
-            *statement = auth;
+          log.debugStream() << "Trying to decode unfiltered attribute response: "
+                << ret.attr_response_pre << CategoryStream::ENDLINE;
+          *attr_response_pre = new SAMLResponse(prestream);
+        }
+
+        // return the filtered Response
+        if (attr_response_post) {
+          istringstream poststream(ret.attr_response_post);
+          
+          log.debugStream() << "Trying to decode filtered attribute response: "
+                << ret.attr_response_post << CategoryStream::ENDLINE;
+          *attr_response_post = new SAMLResponse(poststream);
         }
       }
       catch (SAMLException& e) {
@@ -1185,17 +1219,19 @@ ShibTarget::sessionGet(
  * Shib Target Private implementation
  */
 
-ShibTargetPriv::ShibTargetPriv()
-    : m_app(NULL), m_mapper(NULL), m_conf(NULL), m_Config(NULL), session_id(NULL), m_sso_statement(NULL) {}
+ShibTargetPriv::ShibTargetPriv() : m_app(NULL), m_mapper(NULL), m_conf(NULL), m_Config(NULL), session_id(NULL),
+    m_sso_profile(PROFILE_UNSPECIFIED), m_sso_statement(NULL), m_pre_response(NULL), m_post_response(NULL) {}
 
 ShibTargetPriv::~ShibTargetPriv()
 {
   delete m_sso_statement;
   m_sso_statement = NULL;
 
-  for (int k = 0; k < m_assertions.size(); k++)
-    delete m_assertions[k];
-  m_assertions.clear();
+  delete m_pre_response;
+  m_pre_response = NULL;
+  
+  delete m_post_response;
+  m_post_response = NULL;
 
   if (m_mapper) {
     m_mapper->unlock();
index 97a0c9b..12fb5fb 100644 (file)
@@ -208,8 +208,10 @@ namespace shibtarget {
     {
         virtual bool isValid(time_t lifetime, time_t timeout) const=0;
         virtual const char* getClientAddress() const=0;
+        virtual ShibProfile getProfile() const=0;
+        virtual const char* getProviderId() const=0;
         virtual const saml::SAMLAuthenticationStatement* getAuthnStatement() const=0;
-        virtual saml::Iterator<saml::SAMLAssertion*> getAssertions()=0;
+        virtual const saml::SAMLResponse* getResponse(bool filtered=true)=0;
         virtual ~ISessionCacheEntry() {}
     };
 
@@ -221,8 +223,10 @@ namespace shibtarget {
         virtual void insert(
             const char* key,
             const IApplication* application,
-            saml::SAMLAuthenticationStatement *s,
             const char* client_addr,
+            ShibProfile profile,
+            const char* providerId,
+            saml::SAMLAuthenticationStatement* s,
             saml::SAMLResponse* r=NULL,
             const shibboleth::IRoleDescriptor* source=NULL
             )=0;
@@ -521,19 +525,31 @@ namespace shibtarget {
 
     // Currently wraps remoted interface.
     // TODO: Move this functionality behind ISessionCache
+    RPCError* stateMgr(
+        const char* packet,
+        const char* ip,
+        std::string& cookie
+        ) const;
+    
     RPCError* sessionNew(
-               const char* packet,
-               const char* ip,
-               std::string& cookie,
-                std::string& target
-             ) const;
+        int supported_profiles,
+        const char* packet,
+        const char* statemgr_cookie,
+        const char* ip,
+        std::string& cookie,
+        std::string& target,
+        std::string& statemgr_packet
+        ) const;
 
     RPCError* sessionGet(
-             const char* cookie,
-               const char* ip,
-               std::vector<saml::SAMLAssertion*>& assertions,
-                saml::SAMLAuthenticationStatement **statement = NULL
-              ) const;
+        const char* cookie,
+        const char* ip,
+        ShibProfile& profile,
+        std::string& provider_id,
+        saml::SAMLAuthenticationStatement** auth_statement=NULL,
+        saml::SAMLResponse** attr_response_pre=NULL,
+        saml::SAMLResponse** attr_response_post=NULL
+        ) const;
 
     // Initialize the request from the parsed URL
     // protocol == http, https, etc
index 9b747de..3ac2da3 100644 (file)
@@ -35,3 +35,12 @@ shibrpc_get_session_2(shibrpc_get_session_args_2 *argp, shibrpc_get_session_ret_
                (xdrproc_t) xdr_shibrpc_get_session_ret_2, (caddr_t) clnt_res,
                TIMEOUT));
 }
+
+enum clnt_stat 
+shibrpc_statemgr_2(shibrpc_statemgr_args_2 *argp, shibrpc_statemgr_ret_2 *clnt_res, CLIENT *clnt)
+{
+       return (clnt_call(clnt, shibrpc_statemgr,
+               (xdrproc_t) xdr_shibrpc_statemgr_args_2, (caddr_t) argp,
+               (xdrproc_t) xdr_shibrpc_statemgr_ret_2, (caddr_t) clnt_res,
+               TIMEOUT));
+}
index b99cea2..22730aa 100644 (file)
@@ -42,6 +42,18 @@ shibrpc_get_session_2_svc(shibrpc_get_session_args_2 *argp, shibrpc_get_session_
        return retval;
 }
 
+bool_t
+shibrpc_statemgr_2_svc(shibrpc_statemgr_args_2 *argp, shibrpc_statemgr_ret_2 *result, struct svc_req *rqstp)
+{
+       bool_t retval;
+
+       /*
+        * insert server code here
+        */
+
+       return retval;
+}
+
 int
 shibrpc_prog_2_freeresult (SVCXPRT *transp, xdrproc_t xdr_result, caddr_t result)
 {
index 7054be3..a8809dd 100644 (file)
@@ -138,10 +138,12 @@ shibrpc_get_session_2_svc(
   }
 
   memset (result, 0, sizeof (*result));
-  result->auth_statement.xml_string = strdup("");
-  
-  log.debug ("checking: %s@%s (checkAddr=%s)",
-            argp->cookie, argp->client_addr, argp->checkIPAddress ? "true" : "false");
+  result->provider_id = strdup("");
+  result->auth_statement = strdup("");
+  result->attr_response_pre = strdup("");
+  result->attr_response_post = strdup("");
+
+  log.debug ("checking: %s@%s", argp->cookie, argp->client_addr);
 
   // See if the session exists...
   
@@ -156,6 +158,21 @@ shibrpc_get_session_2_svc(
     return TRUE;
   }
 
+  bool checkIPAddress=true;
+  int lifetime=0,timeout=0;
+  const IPropertySet* props=app->getPropertySet("Sessions");
+  if (props) {
+      pair<bool,unsigned int> p=props->getUnsignedInt("lifetime");
+      if (p.first)
+          lifetime = p.second;
+      p=props->getUnsignedInt("timeout");
+      if (p.first)
+          timeout = p.second;
+      pair<bool,bool> pcheck=props->getBool("checkAddress");
+      if (pcheck.first)
+          checkIPAddress = pcheck.second;
+  }
+    
   ISessionCacheEntry* entry = conf->getSessionCache()->find(argp->cookie,app);
 
   // If not, leave now..
@@ -168,63 +185,54 @@ shibrpc_get_session_2_svc(
   // TEST the session...
   try {
     // Verify the address is the same
-    if (argp->checkIPAddress) {
-      log.debug ("Checking address against %s", entry->getClientAddress());
-      if (strcmp (argp->client_addr, entry->getClientAddress())) {
+    if (checkIPAddress) {
+      log.debug("Checking address against %s", entry->getClientAddress());
+      if (strcmp(argp->client_addr, entry->getClientAddress())) {
         log.debug ("IP Address mismatch");
         Metadata m(app->getMetadataProviders());
         throw ShibTargetException(SHIBRPC_IPADDR_MISMATCH,
             "Your IP address does not match the address recorded at the time the session was established.",
-            m.lookup(entry->getAuthnStatement()->getSubject()->getNameIdentifier()->getNameQualifier()));
+            m.lookup(entry->getProviderId()));
       }
     }
 
     // and that the session is still valid...
-    if (!entry->isValid(argp->lifetime, argp->timeout)) {
+    if (!entry->isValid(lifetime,timeout)) {
       log.debug ("Session expired");
       Metadata m(app->getMetadataProviders());
       throw ShibTargetException(SHIBRPC_SESSION_EXPIRED,
         "Your session has expired, and you must re-authenticate.",
-        m.lookup(entry->getAuthnStatement()->getSubject()->getNameIdentifier()->getNameQualifier()));
+        m.lookup(entry->getProviderId()));
     }
 
     try {
-      // Now grab the serialized authentication statement
+      // Set profile and provider
+      result->profile = entry->getProfile();
+      free(result->provider_id);
+      result->provider_id = strdup(entry->getProviderId());
+     
+      // Now grab the serialized authentication statement and responses
       ostringstream os;
       os << *(entry->getAuthnStatement());
-      free(result->auth_statement.xml_string);
-      result->auth_statement.xml_string = strdup(os.str().c_str());
-     
-      // grab the attributes for this session
-      Iterator<SAMLAssertion*> iter = entry->getAssertions();
-      u_int size = iter.size();
-    
-      // if we have assertions...
-      if (size) {
-          // Build the response section
-          ShibRpcXML* av = (ShibRpcXML*) malloc (size * sizeof (ShibRpcXML));
-    
-          // and then serialize them all...
-          u_int i = 0;
-          while (iter.hasNext()) {
-            SAMLAssertion* as = iter.next();
-            ostringstream os2;
-            os2 << *as;
-            av[i++].xml_string = strdup(os2.str().c_str());
-          }
-    
-          // Set the results, once we know we've succeeded.
-          result->assertions.assertions_len = size;
-          result->assertions.assertions_val = av;
-      }
+      free(result->auth_statement);
+      result->auth_statement = strdup(os.str().c_str());
+      
+      os.str("");
+      os << *(entry->getResponse(false));
+      free(result->attr_response_pre);
+      result->attr_response_pre = strdup(os.str().c_str());
+
+      os.str("");
+      os << *(entry->getResponse(true));
+      free(result->attr_response_post);
+      result->attr_response_post = strdup(os.str().c_str());
     }
     catch (SAMLException &e) {
       log.error ("caught SAML exception: %s", e.what());
       ostringstream os;
       os << e;
       Metadata m(app->getMetadataProviders());
-      throw ShibTargetException(SHIBRPC_SAML_EXCEPTION, os.str().c_str(),
-        m.lookup(entry->getAuthnStatement()->getSubject()->getNameIdentifier()->getNameQualifier()));
+      throw ShibTargetException(SHIBRPC_SAML_EXCEPTION, os.str().c_str(), m.lookup(entry->getProviderId()));
     }
   }
   catch (ShibTargetException &e) {
@@ -295,6 +303,7 @@ shibrpc_new_session_2_svc(
   memset (result, 0, sizeof(*result));
   result->cookie = strdup ("");
   result->target = strdup ("");
+  result->packet = strdup ("");
 
   log.debug ("creating session for %s", argp->client_addr);
   log.debug ("recipient: %s", argp->recipient);
@@ -317,10 +326,16 @@ shibrpc_new_session_2_svc(
       return TRUE;
   }
 
-  // TODO: Sub in call to getReplayCache() as the determinant.
-  // For now, we always have a cache and use the flag...
-  pair<bool,bool> checkReplay=pair<bool,bool>(false,false);
+  bool checkIPAddress=true;
   const IPropertySet* props=app->getPropertySet("Sessions");
+  if (props) {
+      pair<bool,bool> pcheck=props->getBool("checkAddress");
+      if (pcheck.first)
+          checkIPAddress = pcheck.second;
+  }
+
+  pair<bool,bool> checkReplay=pair<bool,bool>(false,false);
+  props=app->getPropertySet("Sessions");
   if (props)
       checkReplay=props->getBool("checkReplay");
  
@@ -363,7 +378,7 @@ shibrpc_new_session_2_svc(
             "Unable to locate role-specific metadata for identity provider", provider);
     
       // Maybe verify the origin address....
-      if (argp->checkIPAddress) {
+      if (checkIPAddress) {
         log.debug ("verify client address");
 
         // Verify the client address exists
@@ -462,6 +477,7 @@ shibrpc_new_session_2_svc(
   }
   
   // Insertion into cache might fail.
+  auto_ptr_char oname(origin);
   SAMLAuthenticationStatement* as=NULL;
   try {
       as=static_cast<SAMLAuthenticationStatement*>(bpr.authnStatement->clone());
@@ -470,8 +486,10 @@ shibrpc_new_session_2_svc(
       conf->getSessionCache()->insert(
         cookie.c_str(),
         app,
-        as,
         argp->client_addr,
+        SAML_11_POST,       // TODO: need to vary this
+        oname.get(),
+        as,
         (attributesPushed ? bpr.response : NULL),
         role
         );
@@ -513,7 +531,6 @@ shibrpc_new_session_2_svc(
   
   // Transaction Logging
   STConfig& stc=static_cast<STConfig&>(ShibTargetConfig::getConfig());
-  auto_ptr_char oname(origin);
   auto_ptr_char hname(as->getSubject()->getNameIdentifier()->getName());
   stc.getTransactionLog().infoStream() <<
     "New session (ID: " <<
@@ -536,6 +553,16 @@ shibrpc_new_session_2_svc(
   return TRUE;
 }
 
+extern "C" bool_t
+shibrpc_statemgr_2_svc(
+    shibrpc_statemgr_args_2 *argp,
+    shibrpc_statemgr_ret_2 *result,
+    struct svc_req *rqstp
+    )
+{
+    return FALSE;
+}
+
 extern "C" int
 shibrpc_prog_2_freeresult (SVCXPRT *transp, xdrproc_t xdr_result, caddr_t result)
 {
index 7bec2e3..9a9521f 100644 (file)
@@ -9,7 +9,6 @@
 #include <rpc/pmap_clnt.h>
 #include <string.h>
 #include <memory.h>
-
 #ifdef WIN32
 # include <winsock.h>
 #else
@@ -28,11 +27,13 @@ shibrpc_prog_2(struct svc_req *rqstp, register SVCXPRT *transp)
                int shibrpc_ping_2_arg;
                shibrpc_new_session_args_2 shibrpc_new_session_2_arg;
                shibrpc_get_session_args_2 shibrpc_get_session_2_arg;
+               shibrpc_statemgr_args_2 shibrpc_statemgr_2_arg;
        } argument;
        union {
                int shibrpc_ping_2_res;
                shibrpc_new_session_ret_2 shibrpc_new_session_2_res;
                shibrpc_get_session_ret_2 shibrpc_get_session_2_res;
+               shibrpc_statemgr_ret_2 shibrpc_statemgr_2_res;
        } result;
        bool_t retval;
        xdrproc_t _xdr_argument, _xdr_result;
@@ -57,6 +58,12 @@ shibrpc_prog_2(struct svc_req *rqstp, register SVCXPRT *transp)
                local = (bool_t (*) (char *, void *,  struct svc_req *))shibrpc_get_session_2_svc;
                break;
 
+       case shibrpc_statemgr:
+               _xdr_argument = (xdrproc_t) xdr_shibrpc_statemgr_args_2;
+               _xdr_result = (xdrproc_t) xdr_shibrpc_statemgr_ret_2;
+               local = (bool_t (*) (char *, void *,  struct svc_req *))shibrpc_statemgr_2_svc;
+               break;
+
        default:
                svcerr_noproc (transp);
                return;
index c0604d8..d01467b 100644 (file)
@@ -58,11 +58,37 @@ xdr_ShibRpcError (XDR *xdrs, ShibRpcError *objp)
 }
 
 bool_t
-xdr_ShibRpcXML (XDR *xdrs, ShibRpcXML *objp)
+xdr_ShibProfile (XDR *xdrs, ShibProfile *objp)
 {
        register int32_t *buf;
 
-        if (!xdr_string (xdrs, &objp->xml_string, ~0))
+        if (!xdr_enum (xdrs, (enum_t *) objp))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_shibrpc_statemgr_args_2 (XDR *xdrs, shibrpc_statemgr_args_2 *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_string (xdrs, &objp->application_id, ~0))
+                return FALSE;
+        if (!xdr_string (xdrs, &objp->packet, ~0))
+                return FALSE;
+        if (!xdr_string (xdrs, &objp->client_addr, ~0))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_shibrpc_statemgr_ret_2 (XDR *xdrs, shibrpc_statemgr_ret_2 *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_ShibRpcError (xdrs, &objp->status))
+                return FALSE;
+        if (!xdr_string (xdrs, &objp->cookie, ~0))
                 return FALSE;
        return TRUE;
 }
@@ -72,16 +98,18 @@ xdr_shibrpc_new_session_args_2 (XDR *xdrs, shibrpc_new_session_args_2 *objp)
 {
        register int32_t *buf;
 
+        if (!xdr_int (xdrs, &objp->supported_profiles))
+                return FALSE;
         if (!xdr_string (xdrs, &objp->application_id, ~0))
                 return FALSE;
         if (!xdr_string (xdrs, &objp->packet, ~0))
                 return FALSE;
+        if (!xdr_string (xdrs, &objp->cookie, ~0))
+                return FALSE;
         if (!xdr_string (xdrs, &objp->recipient, ~0))
                 return FALSE;
         if (!xdr_string (xdrs, &objp->client_addr, ~0))
                 return FALSE;
-        if (!xdr_bool (xdrs, &objp->checkIPAddress))
-                return FALSE;
        return TRUE;
 }
 
@@ -94,6 +122,8 @@ xdr_shibrpc_new_session_ret_2 (XDR *xdrs, shibrpc_new_session_ret_2 *objp)
                 return FALSE;
         if (!xdr_string (xdrs, &objp->target, ~0))
                 return FALSE;
+        if (!xdr_string (xdrs, &objp->packet, ~0))
+                return FALSE;
         if (!xdr_string (xdrs, &objp->cookie, ~0))
                 return FALSE;
        return TRUE;
@@ -110,12 +140,6 @@ xdr_shibrpc_get_session_args_2 (XDR *xdrs, shibrpc_get_session_args_2 *objp)
                 return FALSE;
         if (!xdr_string (xdrs, &objp->client_addr, ~0))
                 return FALSE;
-        if (!xdr_bool (xdrs, &objp->checkIPAddress))
-                return FALSE;
-        if (!xdr_long (xdrs, &objp->lifetime))
-                return FALSE;
-        if (!xdr_long (xdrs, &objp->timeout))
-                return FALSE;
        return TRUE;
 }
 
@@ -126,10 +150,15 @@ xdr_shibrpc_get_session_ret_2 (XDR *xdrs, shibrpc_get_session_ret_2 *objp)
 
         if (!xdr_ShibRpcError (xdrs, &objp->status))
                 return FALSE;
-        if (!xdr_ShibRpcXML (xdrs, &objp->auth_statement))
+        if (!xdr_ShibProfile (xdrs, &objp->profile))
+                return FALSE;
+        if (!xdr_string (xdrs, &objp->provider_id, ~0))
+                return FALSE;
+        if (!xdr_string (xdrs, &objp->auth_statement, ~0))
+                return FALSE;
+        if (!xdr_string (xdrs, &objp->attr_response_pre, ~0))
                 return FALSE;
-        if (!xdr_array (xdrs, (char **)&objp->assertions.assertions_val, (u_int *) &objp->assertions.assertions_len, ~0,
-               sizeof (ShibRpcXML), (xdrproc_t) xdr_ShibRpcXML))
+        if (!xdr_string (xdrs, &objp->attr_response_post, ~0))
                 return FALSE;
        return TRUE;
 }
index f1f45a6..4c6f780 100644 (file)
@@ -50,23 +50,43 @@ struct ShibRpcError {
 };
 typedef struct ShibRpcError ShibRpcError;
 
-struct ShibRpcXML {
-       char *xml_string;
+enum ShibProfile {
+    PROFILE_UNSPECIFIED = 0,
+       SAML_10_POST = 1,
+       SAML_10_ARTIFACT = 2,
+       SAML_11_POST = 4,
+       SAML_11_ARTIFACT = 8,
+       SAML_20_SSO = 16,
 };
-typedef struct ShibRpcXML ShibRpcXML;
+typedef enum ShibProfile ShibProfile;
+
+struct shibrpc_statemgr_args_2 {
+       char *application_id;
+       char *packet;
+       char *client_addr;
+};
+typedef struct shibrpc_statemgr_args_2 shibrpc_statemgr_args_2;
+
+struct shibrpc_statemgr_ret_2 {
+       ShibRpcError status;
+       char *cookie;
+};
+typedef struct shibrpc_statemgr_ret_2 shibrpc_statemgr_ret_2;
 
 struct shibrpc_new_session_args_2 {
+       int supported_profiles;
        char *application_id;
        char *packet;
+       char *cookie;
        char *recipient;
        char *client_addr;
-       bool_t checkIPAddress;
 };
 typedef struct shibrpc_new_session_args_2 shibrpc_new_session_args_2;
 
 struct shibrpc_new_session_ret_2 {
        ShibRpcError status;
        char *target;
+       char *packet;
        char *cookie;
 };
 typedef struct shibrpc_new_session_ret_2 shibrpc_new_session_ret_2;
@@ -75,19 +95,16 @@ struct shibrpc_get_session_args_2 {
        char *application_id;
        char *cookie;
        char *client_addr;
-       bool_t checkIPAddress;
-       long lifetime;
-       long timeout;
 };
 typedef struct shibrpc_get_session_args_2 shibrpc_get_session_args_2;
 
 struct shibrpc_get_session_ret_2 {
        ShibRpcError status;
-       ShibRpcXML auth_statement;
-       struct {
-               u_int assertions_len;
-               ShibRpcXML *assertions_val;
-       } assertions;
+       ShibProfile profile;
+       char *provider_id;
+       char *auth_statement;
+       char *attr_response_pre;
+       char *attr_response_post;
 };
 typedef struct shibrpc_get_session_ret_2 shibrpc_get_session_ret_2;
 
@@ -104,6 +121,9 @@ extern  bool_t shibrpc_new_session_2_svc(shibrpc_new_session_args_2 *, shibrpc_n
 #define shibrpc_get_session 2
 extern  enum clnt_stat shibrpc_get_session_2(shibrpc_get_session_args_2 *, shibrpc_get_session_ret_2 *, CLIENT *);
 extern  bool_t shibrpc_get_session_2_svc(shibrpc_get_session_args_2 *, shibrpc_get_session_ret_2 *, struct svc_req *);
+#define shibrpc_statemgr 3
+extern  enum clnt_stat shibrpc_statemgr_2(shibrpc_statemgr_args_2 *, shibrpc_statemgr_ret_2 *, CLIENT *);
+extern  bool_t shibrpc_statemgr_2_svc(shibrpc_statemgr_args_2 *, shibrpc_statemgr_ret_2 *, struct svc_req *);
 extern int shibrpc_prog_2_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
 
 #else /* K&R C */
@@ -116,6 +136,9 @@ extern  bool_t shibrpc_new_session_2_svc();
 #define shibrpc_get_session 2
 extern  enum clnt_stat shibrpc_get_session_2();
 extern  bool_t shibrpc_get_session_2_svc();
+#define shibrpc_statemgr 3
+extern  enum clnt_stat shibrpc_statemgr_2();
+extern  bool_t shibrpc_statemgr_2_svc();
 extern int shibrpc_prog_2_freeresult ();
 #endif /* K&R C */
 
@@ -125,7 +148,9 @@ extern int shibrpc_prog_2_freeresult ();
 extern  bool_t xdr_ShibRpcStatus (XDR *, ShibRpcStatus*);
 extern  bool_t xdr_ShibRpcErr (XDR *, ShibRpcErr*);
 extern  bool_t xdr_ShibRpcError (XDR *, ShibRpcError*);
-extern  bool_t xdr_ShibRpcXML (XDR *, ShibRpcXML*);
+extern  bool_t xdr_ShibProfile (XDR *, ShibProfile*);
+extern  bool_t xdr_shibrpc_statemgr_args_2 (XDR *, shibrpc_statemgr_args_2*);
+extern  bool_t xdr_shibrpc_statemgr_ret_2 (XDR *, shibrpc_statemgr_ret_2*);
 extern  bool_t xdr_shibrpc_new_session_args_2 (XDR *, shibrpc_new_session_args_2*);
 extern  bool_t xdr_shibrpc_new_session_ret_2 (XDR *, shibrpc_new_session_ret_2*);
 extern  bool_t xdr_shibrpc_get_session_args_2 (XDR *, shibrpc_get_session_args_2*);
@@ -135,7 +160,9 @@ extern  bool_t xdr_shibrpc_get_session_ret_2 (XDR *, shibrpc_get_session_ret_2*)
 extern bool_t xdr_ShibRpcStatus ();
 extern bool_t xdr_ShibRpcErr ();
 extern bool_t xdr_ShibRpcError ();
-extern bool_t xdr_ShibRpcXML ();
+extern bool_t xdr_ShibProfile ();
+extern bool_t xdr_shibrpc_statemgr_args_2 ();
+extern bool_t xdr_shibrpc_statemgr_ret_2 ();
 extern bool_t xdr_shibrpc_new_session_args_2 ();
 extern bool_t xdr_shibrpc_new_session_ret_2 ();
 extern bool_t xdr_shibrpc_get_session_args_2 ();
index d71177c..74e49f1 100644 (file)
@@ -53,39 +53,58 @@ union ShibRpcError switch(ShibRpcStatus status) {
    ShibRpcErr  e;
 };
 
-struct ShibRpcXML {
-  string       xml_string<>;
+/* enumerate profiles/bindings to support */
+enum ShibProfile {
+  PROFILE_UNSPECIFIED = 0,
+  SAML_10_POST = 1,
+  SAML_10_ARTIFACT = 2,
+  SAML_11_POST = 4,
+  SAML_11_ARTIFACT = 8,
+  SAML_20_SSO = 16
 };
 
 /* function argument and response structures */
 
+struct shibrpc_statemgr_args_2 {
+  string       application_id<>;
+  string       packet<>;                               /* opaque state to manage */
+  string       client_addr<>;
+};
+
+struct shibrpc_statemgr_ret_2 {
+  ShibRpcError status;
+  string       cookie<>;                               /* state token returned to caller */
+};
+
 struct shibrpc_new_session_args_2 {
+  int          supported_profiles;             /* bitmask of supported profiles */
   string       application_id<>;
-  string       packet<>;
-  string       recipient<>;
+  string       packet<>;                               /* profile input packet from client */
+  string       cookie<>;                               /* statemgr token, if any */
+  string       recipient<>;                    /* endpoint that received packet */
   string       client_addr<>;
-  bool         checkIPAddress;
 };
 
 struct shibrpc_new_session_ret_2 {
   ShibRpcError status;
-  string       target<>;
-  string       cookie<>;
+  string       target<>;                               /* profile-specific state token from client */
+  string       packet<>;                               /* state token recovered by statemgr, if any */
+  string       cookie<>;                               /* session key manufactured for client */
 };
 
 struct shibrpc_get_session_args_2 {
   string               application_id<>;
-  string               cookie<>;
+  string               cookie<>;                       /* session key provided by client */
   string               client_addr<>;
-  bool                 checkIPAddress;
-  long                 lifetime;
-  long                 timeout;
 };
 
 struct shibrpc_get_session_ret_2 {
   ShibRpcError status;
-  ShibRpcXML   auth_statement;
-  ShibRpcXML   assertions<>;
+  ShibProfile  profile;                                /* profile used in creating session */
+  string               provider_id<>;                  /* authenticating IdP */
+  string               auth_statement<>;               /* SAML authn statement */
+  string               attr_response_pre<>;    /* SAML attr assertions as received */
+  string               attr_response_post<>;   /* SAML attr assertions post-filtering */
 };
 
 
@@ -101,9 +120,11 @@ program SHIBRPC_PROG {
     /* Create a new session for this user (SAML Browser Profile Consumer) */
     shibrpc_new_session_ret_2 shibrpc_new_session (shibrpc_new_session_args_2) = 1;
 
-    /* Validate and access data associated with existing session.
-     * Returns 0 for TRUE, a non-zero error code for FALSE */
+    /* Validate and access data associated with existing session */
     shibrpc_get_session_ret_2 shibrpc_get_session (shibrpc_get_session_args_2) = 2;
 
+       /* Post managed state information for later retrieval during session creation */
+       shibrpc_statemgr_ret_2 shibrpc_statemgr (shibrpc_statemgr_args_2) = 3;
+
   } = 2;
 } = 123456;                    /* Arbitrary RPC Program Number */