Revised metadata interface for multiple sources/providers
authorScott Cantor <cantor.2@osu.edu>
Sat, 17 May 2003 20:37:50 +0000 (20:37 +0000)
committerScott Cantor <cantor.2@osu.edu>
Sat, 17 May 2003 20:37:50 +0000 (20:37 +0000)
shib-target/shib-config.cpp
shib-target/shib-rpcerror.cpp
shib-target/shib-target.h
shib/OriginSiteMapper.cpp
shib/ScopedAttribute.cpp
shib/ShibConfig.cpp
shib/ShibPOSTProfile.cpp
shib/XMLOriginSiteMapper.cpp
shib/internal.h
shib/shib.h

index b3bf50b..17676a1 100644 (file)
@@ -179,12 +179,6 @@ void STConfig::init()
   if (ini->get_tag(app, SHIBTARGET_TAG_AAP, true, &tag))
       shibConf.aapFile=tag;
 
-  if (! ini->get_tag (app, SHIBTARGET_TAG_SITES, true, &tag)) {
-    log.fatal("No Sites File found in configuration");
-    throw runtime_error ("No Sites File found in configuration");
-  }
-  shibConf.mapperFile=tag;
-  
   try { 
     if (!shibConf.init()) {
       log.fatal ("Failed to initialize Shib library");
@@ -217,6 +211,26 @@ void STConfig::init()
     delete iter;
   }
 
+  // Load the specified metadata.
+  bool anyAdded=false;
+  if (ini->get_tag(app, SHIBTARGET_TAG_METADATA, true, &tag) && ini->exists(tag))
+  {
+    ShibINI::Iterator* iter=ini->tag_iterator(tag);
+    for (const string* prov=iter->begin(); prov; prov=iter->next())
+    {
+        const string source=ini->get(tag,*prov);
+        log.info("registering metadata provider: type=%s, source=%s",prov->c_str(),source.c_str());
+        if (shibConf.addMapper(prov->c_str(),source.c_str()))
+            anyAdded=true;
+    }
+    delete iter;
+  }
+  if (!anyAdded)
+  {
+    log.fatal("No metadata providers successfully added");
+    throw runtime_error("No metadata providers successfully added");
+  }
+  
   // Register attributes based on built-in classes.
   if (ini->exists("attributes")) {
     log.info("registering attributes");
index fd1e228..decd4eb 100644 (file)
@@ -263,56 +263,60 @@ const char* RPCError::getDesc()
 
 int RPCError::getCode() { return m_priv->status; }
 
-const char* RPCError::getOriginErrorURL()
+string RPCError::getOriginErrorURL()
 {
-    const char* res=NULL;
-    static const char* msg="No URL Available";
+    string res="No URL Available";
     if (!m_priv->origin.empty())
     {
-        OriginSiteMapper mapper;
-        res=mapper.getErrorURL(m_priv->origin.c_str());
+        OriginSiteMapper mapper(m_priv->origin.c_str());
+        if (!mapper.fail())
+        {
+            const char* temp=mapper->getErrorURL(m_priv->origin.c_str());
+            if (temp)
+                res=temp;
+        }
     }
-    return res ? res : msg;
+    return res;
 }
 
-const char* RPCError::getOriginContactName()
-{
-    const char* res=NULL;
-    static const char* msg="No Name Available";
+string RPCError::getOriginContactName()
+{ 
+    string res="No Name Available";
     if (!m_priv->origin.empty())
     {
-        OriginSiteMapper mapper;
-        Iterator<const IContactInfo*> i=mapper.getContacts(m_priv->origin.c_str());
+        OriginSiteMapper mapper(m_priv->origin.c_str());
+        Iterator<const IContactInfo*> i=
+            mapper.fail() ? Iterator<const IContactInfo*>() : mapper->getContacts(m_priv->origin.c_str());
         while (i.hasNext())
         {
             const IContactInfo* c=i.next();
-            if (c->getType()==IContactInfo::technical)
+            if (c->getType()==IContactInfo::technical && c->getName())
             {
                 res=c->getName();
                 break;
             }
         }
     }
-    return res ? res : msg;
+    return res;
 }
 
-const char* RPCError::getOriginContactEmail()
+string RPCError::getOriginContactEmail()
 {
-    const char* res=NULL;
-    static const char* msg="No Email Available";
+    string res="No Email Available";
     if (!m_priv->origin.empty())
     {
-        OriginSiteMapper mapper;
-        Iterator<const IContactInfo*> i=mapper.getContacts(m_priv->origin.c_str());
+        OriginSiteMapper mapper(m_priv->origin.c_str());
+        Iterator<const IContactInfo*> i=
+            mapper.fail() ? Iterator<const IContactInfo*>() : mapper->getContacts(m_priv->origin.c_str());
         while (i.hasNext())
         {
             const IContactInfo* c=i.next();
-            if (c->getType()==IContactInfo::technical)
+            if (c->getType()==IContactInfo::technical && c->getEmail())
             {
                 res=c->getEmail();
                 break;
             }
         }
     }
-    return res ? res : msg;
+    return res;
 }
index cbab59e..93d4c05 100644 (file)
@@ -83,34 +83,34 @@ void shib_sock_close (ShibSocket s, ShibSockName name);
 /* shib-target.cpp */
 
 /* application names */
-#define SHIBTARGET_GENERAL     "general"
-#define SHIBTARGET_SHAR            "shar"
-#define SHIBTARGET_SHIRE       "shire"
-#define SHIBTARGET_RM          "rm"
+#define SHIBTARGET_GENERAL  "general"
+#define SHIBTARGET_SHAR     "shar"
+#define SHIBTARGET_SHIRE    "shire"
+#define SHIBTARGET_RM           "rm"
 #define SHIBTARGET_POLICIES "policies"
 
 /* configuration tags */
-#define SHIBTARGET_TAG_LOGGER  "logger"
-#define SHIBTARGET_TAG_SCHEMAS "schemadir"
-#define SHIBTARGET_TAG_CERTFILE        "certfile"
-#define SHIBTARGET_TAG_KEYFILE "keyfile"
-#define SHIBTARGET_TAG_KEYPASS "keypass"
-#define SHIBTARGET_TAG_CALIST  "calist"
+#define SHIBTARGET_TAG_LOGGER   "logger"
+#define SHIBTARGET_TAG_SCHEMAS  "schemadir"
+#define SHIBTARGET_TAG_CERTFILE "certfile"
+#define SHIBTARGET_TAG_KEYFILE  "keyfile"
+#define SHIBTARGET_TAG_KEYPASS  "keypass"
+#define SHIBTARGET_TAG_CALIST   "calist"
 
-#define SHIBTARGET_TAG_AATIMEOUT "AATimeout"
-#define SHIBTARGET_TAG_AACONNECTTO "AAConnectTimeout"
-#define SHIBTARGET_TAG_SAMLCOMPAT "SAMLCompat"
+#define SHIBTARGET_TAG_AATIMEOUT    "AATimeout"
+#define SHIBTARGET_TAG_AACONNECTTO  "AAConnectTimeout"
+#define SHIBTARGET_TAG_SAMLCOMPAT   "SAMLCompat"
 
 #define SHIBTARGET_TAG_AAP      "aap-uri"
-#define SHIBTARGET_TAG_SITES   "sitesFile"
+#define SHIBTARGET_TAG_METADATA "metadata"
 
-#define SHIBTARGET_TAG_DEFAULTLIFE     "defaultLife"
+#define SHIBTARGET_TAG_DEFAULTLIFE  "defaultLife"
 
-#define SHIBTARGET_TAG_CACHETYPE       "cacheType"
-#define SHIBTARGET_TAG_CACHECLEAN      "cacheClean"
-#define SHIBTARGET_TAG_CACHETIMEOUT    "cacheTimeout"
+#define SHIBTARGET_TAG_CACHETYPE    "cacheType"
+#define SHIBTARGET_TAG_CACHECLEAN   "cacheClean"
+#define SHIBTARGET_TAG_CACHETIMEOUT "cacheTimeout"
 
-#define SHIBTARGET_TAG_REQATTRS                "requestAttributes"
+#define SHIBTARGET_TAG_REQATTRS     "requestAttributes"
 
 /* initialize and finalize the target library (return 0 on success, 1 on failure) */
 int shib_target_initialize (const char* application, const char* ini_file);
@@ -192,9 +192,9 @@ namespace shibtarget {
     const char* getType();
     const char* getText();
     const char* getDesc();
-    const char* getOriginErrorURL();
-    const char* getOriginContactName();
-    const char* getOriginContactEmail();
+    std::string getOriginErrorURL();
+    std::string getOriginContactName();
+    std::string getOriginContactEmail();
     int getCode();
 
   private:
index 168cf7e..3543b5c 100644 (file)
@@ -47,7 +47,7 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* OriginSiteMapper.h - a mapper implementation that uses an XML-based registry
+/* OriginSiteMapper.h - a wrapper class that insures proper release of mappers
 
    Scott Cantor
    9/27/02
@@ -61,40 +61,25 @@ using namespace shibboleth;
 using namespace saml;
 using namespace std;
 
-OriginSiteMapper::OriginSiteMapper() : m_mapper(ShibConfig::getConfig().getMapper()) {}
-
-OriginSiteMapper::~OriginSiteMapper()
-{
-    ShibConfig::getConfig().releaseMapper(m_mapper);
-}
-
-Iterator<const IContactInfo*> OriginSiteMapper::getContacts(const XMLCh* originSite) const
+OriginSiteMapper::OriginSiteMapper(const XMLCh* originSite) : m_mapper(NULL)
 {
-    return m_mapper->getContacts(originSite);
+    ShibInternalConfig& config=dynamic_cast<ShibInternalConfig&>(ShibConfig::getConfig());
+    config.m_lock->lock();
+    for (ShibInternalConfig::OriginMapperMap::iterator i=config.m_originMap.begin(); i!=config.m_originMap.end(); i++)
+    {
+        i->second->lock();
+        if (i->second->has(originSite))
+        {
+            m_mapper=i->second;
+            break;
+        }
+        i->second->unlock();
+    }
+    config.m_lock->unlock();
 }
 
-const char* OriginSiteMapper::getErrorURL(const XMLCh* originSite) const
-{
-    return m_mapper->getErrorURL(originSite);
-}
-
-Iterator<xstring> OriginSiteMapper::getHandleServiceNames(const XMLCh* originSite) const
-{
-    return m_mapper->getHandleServiceNames(originSite);
-}
-
-XSECCryptoX509* OriginSiteMapper::getHandleServiceCert(const XMLCh* handleService) const
-{
-    return m_mapper->getHandleServiceCert(handleService);
-}
-
-Iterator<pair<xstring,bool> > OriginSiteMapper::getSecurityDomains(const XMLCh* originSite) const
-{
-    return m_mapper->getSecurityDomains(originSite);
-}
-
-time_t OriginSiteMapper::getTimestamp() const
+OriginSiteMapper::~OriginSiteMapper()
 {
-    return m_mapper->getTimestamp();
+    if (m_mapper)
+        m_mapper->unlock();
 }
-
index f25a049..715a3a3 100644 (file)
@@ -99,8 +99,9 @@ bool ScopedAttribute::accept(DOMElement* e) const
     if (!SimpleAttribute::accept(e))
         return false;
 
-    OriginSiteMapper mapper;
-    Iterator<pair<xstring,bool> > domains=mapper.getSecurityDomains(m_originSite.c_str());
+    OriginSiteMapper mapper(m_originSite.c_str());
+    Iterator<pair<xstring,bool> > domains=
+        (mapper.fail()) ? Iterator<pair<xstring,bool> >() : mapper->getSecurityDomains(m_originSite.c_str());
     const XMLCh* this_scope=NULL;
     DOMAttr* scope=e->getAttributeNodeNS(NULL,Scope);
     if (scope)
index 8596d01..1ac0b75 100644 (file)
@@ -68,6 +68,7 @@
 using namespace saml;
 using namespace shibboleth;
 using namespace log4cpp;
+using namespace std;
 
 SAML_EXCEPTION_FACTORY(UnsupportedProtocolException);
 SAML_EXCEPTION_FACTORY(OriginSiteMapperException);
@@ -78,6 +79,16 @@ namespace {
 
 ShibConfig::~ShibConfig() {}
 
+extern "C" IOriginSiteMapper* XMLMapperFactory(const char* source)
+{
+    return new XMLOriginSiteMapper(source,false);
+}
+
+extern "C" IOriginSiteMapper* XMLTrustMapperFactory(const char* source)
+{
+    return new XMLOriginSiteMapper(source,true);
+}
+
 bool ShibInternalConfig::init()
 {
     saml::NDC ndc("init");
@@ -101,91 +112,77 @@ bool ShibInternalConfig::init()
         }
     }
 
-    m_lock=RWLock::create();
+    m_lock=Mutex::create();
     if (!m_lock)
     {
-        Category::getInstance(SHIB_LOGCAT".ShibConfig").fatal("init: failed to create mapper locks");
-        delete m_lock;
-        delete m_AAP;
-        return false;
-    }
-
-    try
-    {
-        m_mapper=new XMLOriginSiteMapper(mapperFile.c_str());
-    }
-    catch(SAMLException& e)
-    {
-        Category::getInstance(SHIB_LOGCAT".ShibConfig").fatal("init: failed to initialize origin site mapper: %s", e.what());
-        delete m_lock;
+        Category::getInstance(SHIB_LOGCAT".ShibConfig").fatal("init: failed to create mapper lock");
         delete m_AAP;
         return false;
     }
+    
+    regFactory("edu.internet2.middleware.shibboleth.metadata.origin.XML",&XMLMapperFactory);
+    regFactory("edu.internet2.middleware.shibboleth.metadata.origin.XMLTrust",&XMLTrustMapperFactory);
 
     return true;
 }
 
 void ShibInternalConfig::term()
 {
-    delete m_mapper;
+    for (OriginMapperMap::iterator i=m_originMap.begin(); i!=m_originMap.end(); i++)
+        delete i->second;
     delete m_lock;
     delete m_AAP;
 }
 
-IOriginSiteMapper* ShibInternalConfig::getMapper()
+void ShibInternalConfig::regFactory(const char* type, OriginSiteMapperFactory* factory)
 {
-    m_lock->rdlock();
-
-    // Check if we need to refresh.
-#ifdef WIN32
-    struct _stat stat_buf;
-    if (_stat(mapperFile.c_str(), &stat_buf) == 0)
-#else
-    struct stat stat_buf;
-    if (stat(mapperFile.c_str(), &stat_buf) == 0)
-#endif
+    if (type && factory)
+        m_originFactoryMap[type]=factory;
+}
+
+void ShibInternalConfig::unregFactory(const char* type)
+{
+    if (type)
+        m_originFactoryMap.erase(type);
+}
+
+bool ShibInternalConfig::addMapper(const char* type, const char* source)
+{
+    saml::NDC ndc("addMapper");
+
+    bool ret=false;
+    m_lock->lock();
+    try
     {
-        if (m_mapper->getTimestamp()>0 && m_mapper->getTimestamp()<stat_buf.st_mtime)
+        OriginMapperFactoryMap::const_iterator i=m_originFactoryMap.find(type);
+        if (i!=m_originFactoryMap.end())
         {
-            // Elevate lock and recheck.
-            m_lock->unlock();
-            m_lock->wrlock();
-            if (m_mapper->getTimestamp()>0 && m_mapper->getTimestamp()<stat_buf.st_mtime)
+            if (m_originMap.find(pair<string,string>(type,source))==m_originMap.end())
             {
-                try
-                {
-                    IOriginSiteMapper* new_mapper=new XMLOriginSiteMapper(mapperFile.c_str());
-                    delete m_mapper;
-                    m_mapper=new_mapper;
-                    m_lock->unlock();
-                }
-                catch(SAMLException& e)
-                {
-                    m_lock->unlock();
-                    saml::NDC ndc("getMapper");
-                    Category::getInstance(SHIB_LOGCAT".ShibConfig").error("failed to reload origin site mapper, sticking with what we have: %s", e.what());
-                }
-                catch(...)
-                {
-                    m_lock->unlock();
-                    saml::NDC ndc("getMapper");
-                    Category::getInstance(SHIB_LOGCAT".ShibConfig").error("caught an unknown exception, sticking with what we have");
-                }
+                m_originMap[pair<string,string>(type,source)]=(i->second)(source);
+                ret=true;
             }
             else
-            {
-                m_lock->unlock();
-            }
-            m_lock->rdlock();
+                throw OriginSiteMapperException("ShibConfig::addMapper() cannot add a duplicate mapper");
         }
+        else
+            throw OriginSiteMapperException("ShibConfig::addMapper() unable to locate a mapper factory of the requested type");
+        
+    }
+    catch (SAMLException& e)
+    {
+        Category::getInstance(SHIB_LOGCAT".ShibConfig").error(
+            "failed to add %s mapper to system using source '%s': %s", type, source, e.what()
+            );
+    }
+    catch (...)
+    {
+        Category::getInstance(SHIB_LOGCAT".ShibConfig").error(
+            "failed to add %s mapper to system using source '%s': unknown exception", type, source
+            );
     }
-    
-    return m_mapper;
-}
-
-void ShibInternalConfig::releaseMapper(IOriginSiteMapper* mapper)
-{
     m_lock->unlock();
+    return ret;
 }
 
 ShibConfig& ShibConfig::getConfig()
index 6126dd8..4c42791 100644 (file)
@@ -159,8 +159,8 @@ SAMLResponse* ShibPOSTProfile::accept(const XMLByte* buf, XMLCh** originSitePtr)
     const XMLCh* handleService = assertion->getIssuer();
 
     // Is this a trusted HS?
-    OriginSiteMapper mapper;
-    Iterator<xstring> hsNames=mapper.getHandleServiceNames(originSite);
+    OriginSiteMapper mapper(originSite);
+    Iterator<xstring> hsNames=mapper.fail() ? Iterator<xstring>() : mapper->getHandleServiceNames(originSite);
     bool bFound = false;
     while (!bFound && hsNames.hasNext())
         if (!XMLString::compareString(hsNames.next().c_str(),handleService))
@@ -168,7 +168,7 @@ SAMLResponse* ShibPOSTProfile::accept(const XMLByte* buf, XMLCh** originSitePtr)
     if (!bFound)
         throw TrustException(SAMLException::RESPONDER, "ShibPOSTProfile::accept() detected an untrusted HS for the origin site");
 
-    XSECCryptoX509* hsCert=mapper.getHandleServiceCert(handleService);
+    XSECCryptoX509* hsCert=mapper->getHandleServiceCert(handleService);
 
     // Signature verification now takes place. We check the assertion and the response.
     // Assertion signing is optional, response signing is mandatory.
index 26d48b6..d59c175 100644 (file)
@@ -61,6 +61,7 @@
 #include <sys/stat.h>
 
 #include <log4cpp/Category.hh>
+#include <xercesc/framework/URLInputSource.hpp>
 #include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>
 
 using namespace shibboleth;
@@ -68,65 +69,88 @@ using namespace saml;
 using namespace log4cpp;
 using namespace std;
 
-#include <xercesc/framework/URLInputSource.hpp>
+class shibboleth::XMLOriginSiteMapperImpl
+{
+public:
+    XMLOriginSiteMapperImpl(const char* pathname, bool loadTrust);
+    ~XMLOriginSiteMapperImpl();
+    
+    struct OriginSite
+    {
+        OriginSite(const XMLCh* errorURL) : m_errorURL(XMLString::transcode(errorURL)) {}
+        ~OriginSite();
 
+        class ContactInfo : public IContactInfo
+        {
+        public:
+            ContactInfo(ContactType type, const XMLCh* name, const XMLCh* email);
+            
+            ContactType getType() const { return m_type; }
+            const char* getName() const { return m_name.get(); }            
+            const char* getEmail() const { return m_email.get(); }
+            
+        private:
+            ContactType m_type;
+            std::auto_ptr<char> m_name, m_email;
+        };
+        
+        std::vector<const IContactInfo*> m_contacts;
+        std::auto_ptr<char> m_errorURL;
+        std::vector<saml::xstring> m_handleServices;
+        std::vector<std::pair<saml::xstring,bool> > m_domains;
+    };
 
-XMLOriginSiteMapper::XMLOriginSiteMapper(const char* pathname) : m_filestamp(0)
-{
-    NDC ndc("XMLOriginSiteMapper");
-    Category& log=Category::getInstance(SHIB_LOGCAT".XMLOriginSiteMapper");
+    std::map<saml::xstring,OriginSite*> m_sites;
+    std::map<saml::xstring,XSECCryptoX509*> m_hsCerts;
+};
 
-#ifdef WIN32
-    struct _stat stat_buf;
-    if (_stat(pathname, &stat_buf) == 0)
-#else
-    struct stat stat_buf;
-    if (stat(pathname, &stat_buf) == 0)
-#endif
-        m_filestamp=stat_buf.st_mtime;
+XMLOriginSiteMapperImpl::XMLOriginSiteMapperImpl(const char* pathname, bool loadTrust)
+{
+    NDC ndc("XMLOriginSiteMapperImpl");
+    Category& log=Category::getInstance(SHIB_LOGCAT".XMLOriginSiteMapperImpl");
 
     saml::XML::Parser p;
     DOMDocument* doc=NULL;
-       try
+    try
     {
         static XMLCh base[]={chLatin_f, chLatin_i, chLatin_l, chLatin_e, chColon, chForwardSlash, chForwardSlash, chForwardSlash, chNull};
         URLInputSource src(base,pathname);
         Wrapper4InputSource dsrc(&src,false);
-               doc=p.parse(dsrc);
+        doc=p.parse(dsrc);
 
         log.infoStream() << "Loaded and parsed site file (" << pathname << ")" << CategoryStream::ENDLINE;
 
-               DOMElement* e = doc->getDocumentElement();
+        DOMElement* e = doc->getDocumentElement();
         if (XMLString::compareString(XML::SHIB_NS,e->getNamespaceURI()) ||
             XMLString::compareString(XML::Literals::Sites,e->getLocalName()))
         {
-                       log.error("Construction requires a valid site file: (shib:Sites as root element)");
-                       throw OriginSiteMapperException("Construction requires a valid site file: (shib:Sites as root element)");
-               }
+            log.error("Construction requires a valid site file: (shib:Sites as root element)");
+            throw OriginSiteMapperException("Construction requires a valid site file: (shib:Sites as root element)");
+        }
 
-               // Loop over the OriginSite elements.
+        // Loop over the OriginSite elements.
         DOMNodeList* nlist = e->getElementsByTagNameNS(XML::SHIB_NS,XML::Literals::OriginSite);
-               for (int i=0; nlist && i<nlist->getLength(); i++)
+        for (int i=0; nlist && i<nlist->getLength(); i++)
         {
             DOMElement* os_e=static_cast<DOMElement*>(nlist->item(i));
             auto_ptr<XMLCh> os_name(XMLString::replicate(os_e->getAttributeNS(NULL,XML::Literals::Name)));
             XMLString::trim(os_name.get());
-                       if (!os_name.get() || !*os_name)
-                               continue;
+            if (!os_name.get() || !*os_name)
+                continue;
 
-                       OriginSite* os_obj = new OriginSite(os_e->getAttributeNS(NULL,XML::Literals::ErrorURL));
-                       m_sites[os_name.get()]=os_obj;
+            OriginSite* os_obj = new OriginSite(os_e->getAttributeNS(NULL,XML::Literals::ErrorURL));
+            m_sites[os_name.get()]=os_obj;
 
-                       DOMNode* os_child = nlist->item(i)->getFirstChild();
-                       while (os_child)
+            DOMNode* os_child = nlist->item(i)->getFirstChild();
+            while (os_child)
             {
                 if (os_child->getNodeType()!=DOMNode::ELEMENT_NODE)
                 {
-                                       os_child = os_child->getNextSibling();
-                                       continue;
-                               }
+                    os_child = os_child->getNextSibling();
+                    continue;
+                }
 
-                               // Process the various kinds of OriginSite children that we care about...
+                // Process the various kinds of OriginSite children that we care about...
                 if (!XMLString::compareString(XML::SHIB_NS,os_child->getNamespaceURI()) &&
                     !XMLString::compareString(XML::Literals::Contact,os_child->getLocalName()))
                 {
@@ -148,33 +172,33 @@ XMLOriginSiteMapper::XMLOriginSiteMapper(const char* pathname) : m_filestamp(0)
                     os_obj->m_contacts.push_back(cinfo);
                 }
                 else if (!XMLString::compareString(XML::SHIB_NS,os_child->getNamespaceURI()) &&
-                                             !XMLString::compareString(XML::Literals::HandleService,os_child->getLocalName()))
+                       !XMLString::compareString(XML::Literals::HandleService,os_child->getLocalName()))
                 {
                     auto_ptr<XMLCh> hs_name(XMLString::replicate(static_cast<DOMElement*>(os_child)->getAttributeNS(NULL,XML::Literals::Name)));
                     XMLString::trim(hs_name.get());
 
-                                       if (hs_name.get() && *hs_name)
+                    if (hs_name.get() && *hs_name)
                     {
-                                               os_obj->m_handleServices.push_back(hs_name.get());
+                        os_obj->m_handleServices.push_back(hs_name.get());
 
                         // Look for ds:KeyInfo.
-                                               DOMNode* ki=os_child->getFirstChild();
+                        DOMNode* ki=os_child->getFirstChild();
                         while (ki && ki->getNodeType()!=DOMNode::ELEMENT_NODE)
-                                                       ki=ki->getNextSibling();
+                            ki=ki->getNextSibling();
                         if (ki && !XMLString::compareString(saml::XML::XMLSIG_NS,ki->getNamespaceURI()) &&
                             !XMLString::compareString(saml::XML::Literals::KeyInfo,ki->getNamespaceURI()))
                         {
                             // Look for ds:X509Data.
                             DOMNode* xdata=ki->getFirstChild();
                             while (xdata && xdata->getNodeType()!=DOMNode::ELEMENT_NODE)
-                                                           xdata=xdata->getNextSibling();
+                                xdata=xdata->getNextSibling();
                             if (xdata && !XMLString::compareString(saml::XML::XMLSIG_NS,xdata->getNamespaceURI()) &&
                                 !XMLString::compareString(saml::XML::Literals::X509Data,xdata->getNamespaceURI()))
                             {
                                 // Look for ds:X509Certificate.
                                 DOMNode* x509=xdata->getFirstChild();
                                 while (x509 && x509->getNodeType()!=DOMNode::ELEMENT_NODE)
-                                                               x509=x509->getNextSibling();
+                                    x509=x509->getNextSibling();
                                 if (x509 && !XMLString::compareString(saml::XML::XMLSIG_NS,x509->getNamespaceURI()) &&
                                     !XMLString::compareString(saml::XML::Literals::X509Certificate,x509->getNamespaceURI()))
                                 {
@@ -184,44 +208,46 @@ XMLOriginSiteMapper::XMLOriginSiteMapper(const char* pathname) : m_filestamp(0)
                                     m_hsCerts[hs_name.get()]=cert;
                                 }
                             }
-                                               }
-                                       }
-                               }
+                        }
+                    }
+                }
                 else if (!XMLString::compareString(XML::SHIB_NS,os_child->getNamespaceURI()) &&
-                                            !XMLString::compareString(XML::Literals::Domain,os_child->getLocalName()))
+                            !XMLString::compareString(XML::Literals::Domain,os_child->getLocalName()))
                 {
                     auto_ptr<XMLCh> dom(XMLString::replicate(os_child->getFirstChild()->getNodeValue()));
                     XMLString::trim(dom.get());
-                                       if (dom.get() && *dom)
+                    if (dom.get() && *dom)
                     {
                         static const XMLCh one[]={ chDigit_1, chNull };
                         static const XMLCh tru[]={ chLatin_t, chLatin_r, chLatin_u, chLatin_e, chNull };
                         const XMLCh* regexp=static_cast<DOMElement*>(os_child)->getAttributeNS(NULL,XML::Literals::regexp);
                         bool flag=(!XMLString::compareString(regexp,one) || !XMLString::compareString(regexp,tru));
-                                               os_obj->m_domains.push_back(pair<xstring,bool>(dom.get(),flag));
+                        os_obj->m_domains.push_back(pair<xstring,bool>(dom.get(),flag));
                     }
-                               }
-                               os_child = os_child->getNextSibling();
-                       }
-               }
+                }
+                os_child = os_child->getNextSibling();
+            }
+        }
     }
     catch (SAMLException& e)
     {
-               log.errorStream() << "XML error while parsing site configuration: " << e.what() << CategoryStream::ENDLINE;
+        log.errorStream() << "XML error while parsing site configuration: " << e.what() << CategoryStream::ENDLINE;
         if (doc)
             doc->release();
-               throw;
-       }
+        throw;
+    }
     catch (...)
     {
-               log.error("Unexpected error while parsing site configuration");
+        log.error("Unexpected error while parsing site configuration");
         if (doc)
             doc->release();
-               throw;
+        throw;
     }
+    if (doc)
+        doc->release();
 }
 
-XMLOriginSiteMapper::~XMLOriginSiteMapper()
+XMLOriginSiteMapperImpl::~XMLOriginSiteMapperImpl()
 {
     for (map<xstring,OriginSite*>::iterator i=m_sites.begin(); i!=m_sites.end(); i++)
         delete i->second;
@@ -229,49 +255,129 @@ XMLOriginSiteMapper::~XMLOriginSiteMapper()
         delete j->second;
 }
 
-XMLOriginSiteMapper::OriginSite::ContactInfo::ContactInfo(ContactType type, const XMLCh* name, const XMLCh* email)
+XMLOriginSiteMapper::XMLOriginSiteMapper(const char* pathname, bool loadTrust)
+    : m_filestamp(0), m_source(pathname), m_trust(loadTrust), m_impl(NULL)
+{
+#ifdef WIN32
+    struct _stat stat_buf;
+    if (_stat(pathname, &stat_buf) == 0)
+#else
+    struct stat stat_buf;
+    if (stat(pathname, &stat_buf) == 0)
+#endif
+        m_filestamp=stat_buf.st_mtime;
+    m_impl=new XMLOriginSiteMapperImpl(pathname,loadTrust);
+    m_lock=RWLock::create();
+}
+
+XMLOriginSiteMapperImpl::OriginSite::ContactInfo::ContactInfo(ContactType type, const XMLCh* name, const XMLCh* email)
     : m_type(type), m_name(XMLString::transcode(name)), m_email(XMLString::transcode(email)) {}
 
-XMLOriginSiteMapper::OriginSite::~OriginSite()
+XMLOriginSiteMapperImpl::OriginSite::~OriginSite()
 {
     for (vector<const IContactInfo*>::iterator i=m_contacts.begin(); i!=m_contacts.end(); i++)
         delete const_cast<IContactInfo*>(*i);
 }
 
+XMLOriginSiteMapper::~XMLOriginSiteMapper()
+{
+    delete m_lock;
+    delete m_impl;
+}
+
+void XMLOriginSiteMapper::lock()
+{
+    m_lock->rdlock();
+
+    // Check if we need to refresh.
+#ifdef WIN32
+    struct _stat stat_buf;
+    if (_stat(m_source.c_str(), &stat_buf) == 0)
+#else
+    struct stat stat_buf;
+    if (stat(m_source.c_str(), &stat_buf) == 0)
+#endif
+    {
+        if (m_filestamp>0 && m_filestamp<stat_buf.st_mtime)
+        {
+            // Elevate lock and recheck.
+            m_lock->unlock();
+            m_lock->wrlock();
+            if (m_filestamp>0 && m_filestamp<stat_buf.st_mtime)
+            {
+                try
+                {
+                    XMLOriginSiteMapperImpl* new_mapper=new XMLOriginSiteMapperImpl(m_source.c_str(),m_trust);
+                    delete m_impl;
+                    m_impl=new_mapper;
+                    m_lock->unlock();
+                }
+                catch(SAMLException& e)
+                {
+                    m_lock->unlock();
+                    saml::NDC ndc("lock");
+                    Category::getInstance(SHIB_LOGCAT".XMLOriginSiteMapper").error("failed to reload metadata, sticking with what we have: %s", e.what());
+                }
+                catch(...)
+                {
+                    m_lock->unlock();
+                    saml::NDC ndc("lock");
+                    Category::getInstance(SHIB_LOGCAT".XMLOriginSiteMapper").error("caught an unknown exception, sticking with what we have");
+                }
+            }
+            else
+            {
+                m_lock->unlock();
+            }
+            m_lock->rdlock();
+        }
+    }
+}
+
+void XMLOriginSiteMapper::unlock()
+{
+    m_lock->unlock();
+}
+
+bool XMLOriginSiteMapper::has(const XMLCh* originSite) const
+{
+    return m_impl->m_sites.find(originSite)!=m_impl->m_sites.end();
+}
+
 Iterator<const IContactInfo*> XMLOriginSiteMapper::getContacts(const XMLCh* originSite) const
 {
-    map<xstring,OriginSite*>::const_iterator i=m_sites.find(originSite);
-    if (i==m_sites.end())
+    map<xstring,XMLOriginSiteMapperImpl::OriginSite*>::const_iterator i=m_impl->m_sites.find(originSite);
+    if (i==m_impl->m_sites.end())
         return Iterator<const IContactInfo*>();
     return Iterator<const IContactInfo*>(i->second->m_contacts);
 }
 
 const char* XMLOriginSiteMapper::getErrorURL(const XMLCh* originSite) const
 {
-    map<xstring,OriginSite*>::const_iterator i=m_sites.find(originSite);
-    if (i==m_sites.end())
+    map<xstring,XMLOriginSiteMapperImpl::OriginSite*>::const_iterator i=m_impl->m_sites.find(originSite);
+    if (i==m_impl->m_sites.end())
         return NULL;
     return i->second->m_errorURL.get();
 }
 
 Iterator<xstring> XMLOriginSiteMapper::getHandleServiceNames(const XMLCh* originSite) const
 {
-    map<xstring,OriginSite*>::const_iterator i=m_sites.find(originSite);
-    if (i==m_sites.end())
+    map<xstring,XMLOriginSiteMapperImpl::OriginSite*>::const_iterator i=m_impl->m_sites.find(originSite);
+    if (i==m_impl->m_sites.end())
         return Iterator<xstring>();
     return Iterator<xstring>(i->second->m_handleServices);
 }
 
 XSECCryptoX509* XMLOriginSiteMapper::getHandleServiceCert(const XMLCh* handleService) const
 {
-    map<xstring,XSECCryptoX509*>::const_iterator i=m_hsCerts.find(handleService);
-    return (i!=m_hsCerts.end()) ? i->second : NULL;
+    map<xstring,XSECCryptoX509*>::const_iterator i=m_impl->m_hsCerts.find(handleService);
+    return (i!=m_impl->m_hsCerts.end()) ? i->second : NULL;
 }
 
 Iterator<pair<xstring,bool> > XMLOriginSiteMapper::getSecurityDomains(const XMLCh* originSite) const
 {
-    map<xstring,OriginSite*>::const_iterator i=m_sites.find(originSite);
-    if (i==m_sites.end())
+    map<xstring,XMLOriginSiteMapperImpl::OriginSite*>::const_iterator i=m_impl->m_sites.find(originSite);
+    if (i==m_impl->m_sites.end())
         return Iterator<pair<xstring,bool> >();
     return Iterator<pair<xstring,bool> >(i->second->m_domains);
 }
index 6328deb..fcaa107 100644 (file)
 
 namespace shibboleth
 {
+    class XMLOriginSiteMapperImpl;
     class SHIB_EXPORTS XMLOriginSiteMapper : public IOriginSiteMapper
     {
     public:
-        XMLOriginSiteMapper(const char* pathname);
+        XMLOriginSiteMapper(const char* pathname, bool loadTrust);
         ~XMLOriginSiteMapper();
 
-        virtual saml::Iterator<const IContactInfo*> getContacts(const XMLCh* originSite) const;
-        virtual const char* getErrorURL(const XMLCh* originSite) const;
-        virtual saml::Iterator<saml::xstring> getHandleServiceNames(const XMLCh* originSite) const;
-        virtual XSECCryptoX509* getHandleServiceCert(const XMLCh* handleService) const;
-        virtual saml::Iterator<std::pair<saml::xstring,bool> > getSecurityDomains(const XMLCh* originSite) const;
-        virtual time_t getTimestamp() const { return m_filestamp; }
+        void lock();
+        void unlock();
 
-    private:
-        struct OriginSite
-        {
-            OriginSite(const XMLCh* errorURL) : m_errorURL(XMLString::transcode(errorURL)) {}
-            ~OriginSite();
+        bool has(const XMLCh* originSite) const;
+        saml::Iterator<const IContactInfo*> getContacts(const XMLCh* originSite) const;
+        const char* getErrorURL(const XMLCh* originSite) const;
+        saml::Iterator<saml::xstring> getHandleServiceNames(const XMLCh* originSite) const;
+        XSECCryptoX509* getHandleServiceCert(const XMLCh* handleService) const;
+        saml::Iterator<std::pair<saml::xstring,bool> > getSecurityDomains(const XMLCh* originSite) const;
+        time_t getTimestamp() const { return m_filestamp; }
 
-            class ContactInfo : public IContactInfo
-            {
-            public:
-                ContactInfo(ContactType type, const XMLCh* name, const XMLCh* email);
-                
-                ContactType getType() const { return m_type; }
-                const char* getName() const { return m_name.get(); }            
-                const char* getEmail() const { return m_email.get(); }
-                
-            private:
-                ContactType m_type;
-                std::auto_ptr<char> m_name, m_email;
-            };
-            
-            std::vector<const IContactInfo*> m_contacts;
-            std::auto_ptr<char> m_errorURL;
-            std::vector<saml::xstring> m_handleServices;
-            std::vector<std::pair<saml::xstring,bool> > m_domains;
-        };
-
-        std::map<saml::xstring,OriginSite*> m_sites;
-        std::map<saml::xstring,XSECCryptoX509*> m_hsCerts;
+    private:
+        std::string m_source;
+        bool m_trust;
         time_t m_filestamp;
+        RWLock* m_lock;
+        XMLOriginSiteMapperImpl* m_impl;
     };
 
     class AAP
@@ -148,19 +130,27 @@ namespace shibboleth
     class ShibInternalConfig : public ShibConfig
     {
     public:
-        ShibInternalConfig() : m_AAP(NULL), m_mapper(NULL), m_lock(NULL) {}
+        ShibInternalConfig() : m_AAP(NULL), m_lock(NULL) {}
 
-        // global per-process setup and shutdown of runtime
         bool init();
         void term();
 
-        IOriginSiteMapper* getMapper();
-        void releaseMapper(IOriginSiteMapper* mapper);
+        void regFactory(const char* type, OriginSiteMapperFactory* factory);
+        void unregFactory(const char* type);
+        
+        bool addMapper(const char* type, const char* source);
 
         AAP* m_AAP;
+        
     private:
-        IOriginSiteMapper* m_mapper;
-        RWLock* m_lock;
+        friend class OriginSiteMapper;
+        
+        typedef std::map<std::string, OriginSiteMapperFactory*> OriginMapperFactoryMap;
+        OriginMapperFactoryMap m_originFactoryMap;
+        
+        typedef std::map<std::pair<std::string, std::string>, IOriginSiteMapper*> OriginMapperMap;
+        OriginMapperMap m_originMap;
+        Mutex* m_lock;
     };
 }
 
index e300be3..b2a30a6 100644 (file)
@@ -114,35 +114,6 @@ namespace shibboleth
     template class SHIB_EXPORTS saml::ArrayIterator<const IContactInfo*>;
 #endif
 
-    struct SHIB_EXPORTS IOriginSiteMapper
-    {
-        virtual saml::Iterator<const IContactInfo*> getContacts(const XMLCh* originSite) const=0;
-        virtual const char* getErrorURL(const XMLCh* originSite) const=0;
-        virtual saml::Iterator<saml::xstring> getHandleServiceNames(const XMLCh* originSite) const=0;
-        virtual XSECCryptoX509* getHandleServiceCert(const XMLCh* handleService) const=0;
-        virtual saml::Iterator<std::pair<saml::xstring,bool> > getSecurityDomains(const XMLCh* originSite) const=0;
-        virtual time_t getTimestamp() const=0;
-        virtual ~IOriginSiteMapper() {};
-    };
-
-    class SHIB_EXPORTS OriginSiteMapper : public IOriginSiteMapper
-    {
-    public:
-        OriginSiteMapper();
-        ~OriginSiteMapper();
-        virtual saml::Iterator<const IContactInfo*> getContacts(const XMLCh* originSite) const;
-        virtual const char* getErrorURL(const XMLCh* originSite) const;
-        virtual saml::Iterator<saml::xstring> getHandleServiceNames(const XMLCh* originSite) const;
-        virtual XSECCryptoX509* getHandleServiceCert(const XMLCh* handleService) const;
-        virtual saml::Iterator<std::pair<saml::xstring,bool> > getSecurityDomains(const XMLCh* originSite) const;
-        virtual time_t getTimestamp() const;
-
-    private:
-        OriginSiteMapper(const OriginSiteMapper&);
-        void operator=(const OriginSiteMapper&);
-        IOriginSiteMapper* m_mapper;
-    };
-
     class SHIB_EXPORTS SimpleAttribute : public saml::SAMLAttribute
     {
     public:
@@ -256,6 +227,39 @@ namespace shibboleth
         static ShibPOSTProfile* getInstance(const saml::Iterator<const XMLCh*>& policies, const XMLCh* issuer);
     };
 
+    // Metadata abstract interface
+    struct SHIB_EXPORTS IOriginSiteMapper
+    {
+        virtual void lock()=0;
+        virtual void unlock()=0;
+        
+        virtual bool has(const XMLCh* originSite) const=0;
+        virtual saml::Iterator<const IContactInfo*> getContacts(const XMLCh* originSite) const=0;
+        virtual const char* getErrorURL(const XMLCh* originSite) const=0;
+        virtual saml::Iterator<saml::xstring> getHandleServiceNames(const XMLCh* originSite) const=0;
+        virtual XSECCryptoX509* getHandleServiceCert(const XMLCh* handleService) const=0;
+        virtual saml::Iterator<std::pair<saml::xstring,bool> > getSecurityDomains(const XMLCh* originSite) const=0;
+        virtual time_t getTimestamp() const=0;
+        virtual ~IOriginSiteMapper() {};
+    };
+
+    // Helper class to hide synchronization details
+    class SHIB_EXPORTS OriginSiteMapper
+    {
+    public:
+        OriginSiteMapper(const XMLCh* originSite);
+        ~OriginSiteMapper();
+        bool fail() const {return m_mapper==NULL;}
+        const IOriginSiteMapper* operator->() const {return m_mapper;}
+
+    private:
+        OriginSiteMapper(const OriginSiteMapper&);
+        void operator=(const OriginSiteMapper&);
+        IOriginSiteMapper* m_mapper;
+    };
+
+    extern "C" { typedef IOriginSiteMapper* OriginSiteMapperFactory(const char* source); }
+    
     class SHIB_EXPORTS ShibConfig
     {
     public:
@@ -269,12 +273,15 @@ namespace shibboleth
         // enables runtime and clients to access configuration
         static ShibConfig& getConfig();
 
-        virtual IOriginSiteMapper* getMapper()=0;
-        virtual void releaseMapper(IOriginSiteMapper* mapper)=0;
-
+        // allows pluggable implementations of metadata mappers
+        virtual void regFactory(const char* type, OriginSiteMapperFactory* factory)=0;
+        virtual void unregFactory(const char* type)=0;
+        
+        // builds a specific metadata lookup object
+        virtual bool addMapper(const char* type, const char* source)=0;
+        
     /* start of external configuration */
         std::string aapFile;
-        std::string mapperFile;
     /* end of external configuration */
     };