Redesigned target around URL->application mapping
authorcantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Sat, 17 Jan 2004 22:57:14 +0000 (22:57 +0000)
committercantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Sat, 17 Jan 2004 22:57:14 +0000 (22:57 +0000)
git-svn-id: https://svn.middleware.georgetown.edu/cpp-sp/trunk@782 cb58f699-b61c-0410-a6fe-9272a202ed29

42 files changed:
configs/shibboleth.ini.in
isapi_shib/isapi_shib.cpp
mod_shibrm/mod_shibrm.cpp
mod_shire/mod_shire.cpp
schemas/shibboleth-appmap-1.0.xsd
shib-mysql-ccache/shib-mysql-ccache.cpp
shib-target/Makefile.am
shib-target/XMLApplicationMapper.cpp
shib-target/ccache-utils.h
shib-target/internal.h
shib-target/shib-ccache.cpp
shib-target/shib-config.cpp
shib-target/shib-resource.cpp [deleted file]
shib-target/shib-resourceentry.cpp
shib-target/shib-rm.cpp
shib-target/shib-rpcerror.cpp
shib-target/shib-shire.cpp
shib-target/shib-target.h
shib-target/shibrpc-server.cpp
shib-target/shibrpc-svc.c
shib-target/shibrpc-xdr.c
shib-target/shibrpc.h
shib-target/shibrpc.x
shib-target/shibtarget.dsp
shib/AAP.cpp
shib/ClubShibPOSTProfile.cpp
shib/Makefile.am
shib/Metadata.cpp
shib/ReloadableXMLFile.cpp [new file with mode: 0644]
shib/SAMLBindingFactory.cpp
shib/ScopedAttribute.cpp
shib/ShibConfig.cpp
shib/ShibPOSTProfile.cpp
shib/ShibPOSTProfileFactory.cpp
shib/ShibSOAPBinding.cpp
shib/SimpleAttribute.cpp [deleted file]
shib/XMLCredentials.cpp
shib/XMLMetadata.cpp
shib/XMLTrust.cpp
shib/internal.h
shib/shib.dsp
shib/shib.h

index 059a832..bef4887 100644 (file)
@@ -5,7 +5,19 @@ sharsocket=/tmp/shar-socket
 
 # SERVER CONFIGURATION
 
-# Optional, may also be set per-server (or per-directory in Apache)
+# Mandatory
+providerID = https://wayf.internet2.edu/InQueue/ServiceProvider
+wayfURL = https://wayf.internet2.edu/InQueue/WAYF
+cookieName = shib-cookie
+shireSSLOnly = false
+shireError=@-PKGSYSCONFDIR-@/shireError.html
+rmError=@-PKGSYSCONFDIR-@/rmError.html
+accessError=@-PKGSYSCONFDIR-@/accessError.html
+shireURL = /Shibboleth.shire
+
+# Optional, may also be set per-application (some are per-directory in Apache)
+#requireSession = false
+#requestAttributes = 
 #normalizeRequest = true
 #checkIPAddress = false
 #contentSSLOnly = false
@@ -18,26 +30,14 @@ sharsocket=/tmp/shar-socket
 supportContact=admin@your.site
 logoLocation=/logo.gif
 
-# Mandatory
-wayfURL = https://wayf.internet2.edu/InQueue/WAYF
-cookieName = shib-cookie
-shireSSLOnly = false
-shireError=@-PKGSYSCONFDIR-@/shireError.html
-rmError=@-PKGSYSCONFDIR-@/rmError.html
-accessError=@-PKGSYSCONFDIR-@/accessError.html
-
-# Mandatory for IIS, set for Apache with SHIREURL command
-shireURL = /Shibboleth.shire
-
 [shire]
 logger=@-PKGSYSCONFDIR-@/shire.logger
-metadata=metadata_shire
+#applicationMap=@-PKGSYSCONFDIR-@/applications.xml
 
 [shar]
 logger=@-PKGSYSCONFDIR-@/shar.logger
 # If using a TCP-based SHAR, space delimit the allowed client IPs
 #sharacl = 127.0.0.1
-metadata=metadata_shar
 
 # Controls timeouts for AA queries (in seconds)
 AATimeout=60
@@ -65,18 +65,20 @@ mysql = @-LIBEXECDIR-@/shib-mysql-ccache.so
 arg1 = --language=@-PREFIX-@/share/english
 arg2 = --datadir=@-PREFIX-@/data
 
-[metadata_shire]
+[metadata]
 edu.internet2.middleware.shibboleth.metadata.provider.XML=@-PKGSYSCONFDIR-@/sites.xml
+
+[aap]
 edu.internet2.middleware.shibboleth.target.AAP.provider.XML=@-PKGSYSCONFDIR-@/AAP.xml
 
-[metadata_shar]
-edu.internet2.middleware.shibboleth.metadata.provider.XML=@-PKGSYSCONFDIR-@/sites.xml
-edu.internet2.middleware.shibboleth.trust.provider.XML=@-PKGSYSCONFDIR-@/trust.xml
+[creds]
 edu.internet2.middleware.shibboleth.creds.provider.XML=@-PKGSYSCONFDIR-@/creds.xml
-edu.internet2.middleware.shibboleth.target.AAP.provider.XML=@-PKGSYSCONFDIR-@/AAP.xml
+
+[trust]
+edu.internet2.middleware.shibboleth.trust.provider.XML=@-PKGSYSCONFDIR-@/trust.xml
 
 [isapi]
-# When using the ISAPI filter version, map IIS Instance IDs to server names.
+# When using the ISAPI filter version, map IIS Instance IDs to server hostnames.
 # 
 #1=my.server.name
 
@@ -85,18 +87,14 @@ edu.internet2.middleware.shibboleth.target.AAP.provider.XML=@-PKGSYSCONFDIR-@/AA
 # You can filter incoming users at a high level by listing the policies to allow.
 InQueue=urn:mace:inqueue
 
-# To define per-server or per-vhost settings, create a section
-# for the server's hostname and set or override configuration.
-#[my.server.name]
+# To define per-application settings, create a section
+# for the application's ID and set or override configuration.
+#[my_application]
 #normalizeRequest = true
 #checkIPAddress = false
 #contentSSLOnly = false
 #authLifetime = 7200
 #authTimeout = 3600
 #exportAssertion = false
-# For IIS, determine what content to protect by specifying strings
-# to match against the request path. Separate matches with semicolons.
-#mustContain = /secure/;/protected/
-# list of attributes to request for server "my.server.name"
-# requests everything if this doesn't exist or is empty
+#requireSession = true
 #requestAttributes = 
index f59d8a6..ab3c9b2 100644 (file)
@@ -77,21 +77,12 @@ using namespace saml;
 using namespace shibboleth;
 using namespace shibtarget;
 
-struct settings_t
-{
-    settings_t() {}
-    settings_t(string& name) : m_name(name) {}
-    
-    string m_name;
-    vector<string> m_mustContain;
-};
-
 // globals
 namespace {
     HINSTANCE g_hinstDLL;
     ThreadKey* rpc_handle_key = NULL;
     ShibTargetConfig* g_Config = NULL;
-    vector<settings_t> g_Sites;
+    vector<string> g_Sites;
 }
 
 void destroy_handle(void* data)
@@ -163,36 +154,13 @@ extern "C" BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer)
             log.info("configuring for site ID (%d), hostname (%s)",i-1,hostname.empty() ? "null" : hostname.c_str());
 
             // If no section exists for the host, mark it as a "skip" site.
-            if (!ini.exists(hostname))
+            if (hostname == "skip")
             {
                 log.info("skipping site ID (%d)",i-1);
-                g_Sites.push_back(settings_t());
-                sprintf(iid,"%u",i++);
-                continue;
-            }
-            
-            settings_t settings(hostname);
-            
-            // Content matching string.
-            string mustcontain;
-            if (ini.get_tag(hostname,"mustContain",true,&mustcontain) && !mustcontain.empty())
-            {
-                char* buf=strdup(mustcontain.c_str());
-                _strupr(buf);
-                char* start=buf;
-                while (char* sep=strchr(start,';'))
-                {
-                    *sep='\0';
-                    if (*start)
-                        settings.m_mustContain.push_back(start);
-                    start=sep+1;
-                }
-                if (*start)
-                    settings.m_mustContain.push_back(start);
-                free(buf);
+                hostname.erase();
             }
-            
-            g_Sites.push_back(settings);
+
+            g_Sites.push_back(hostname);
             sprintf(iid,"%u",i++);
             hostname.erase();
         }
@@ -370,46 +338,40 @@ string url_encode(const char* url) throw (bad_alloc)
     return s;
 }
 
-string get_target(PHTTP_FILTER_CONTEXT pfc, PHTTP_FILTER_PREPROC_HEADERS pn, settings_t& site)
+void get_target_and_appid(
+    PHTTP_FILTER_CONTEXT pfc, PHTTP_FILTER_PREPROC_HEADERS pn, const char* hostname, string& target, string& appid
+    )
 {
-    // Reconstructing the requested URL is not fun. Apparently, the PREPROC_HEADERS
-    // event means way pre. As in, none of the usual CGI headers are in place yet.
-    // It's actually almost easier, in a way, because all the path-info and query
-    // stuff is in one place, the requested URL, which we can get. But we have to
-    // reconstruct the protocol/host pair using tweezers.
-    string s;
-    if (pfc->fIsSecurePort)
-        s="https://";
-    else
-        s="http://";
+    dynabuf port(10);
+    dynabuf url(256);
+    GetServerVariable(pfc,"SERVER_PORT",port,10);
+    GetHeader(pn,pfc,"url",url,256,false);
+    
+    // First get the appid using the normalized hostname.
+    ApplicationMapper mapper;
+    appid = mapper->getApplicationFromParsedURL((pfc->fIsSecurePort ? "https" : "http"), hostname, atoi(port), url);
 
-    // We use the "normalizeRequest" tag to decide how to obtain the server's name.
-    dynabuf buf(256);
+    target=static_cast<char*>(url);
+    if (port!=(pfc->fIsSecurePort ? "443" : "80"))
+        target = ':' + static_cast<char*>(port) + target;
+
+    // For the target, we use the "normalizeRequest" tag to decide how to set the server's name.
     string tag;
-    if (g_Config->getINI().get_tag(site.m_name,"normalizeRequest",true,&tag) && ShibINI::boolean(tag))
+    if (g_Config->getINI().get_tag(appid,"normalizeRequest",true,&tag) && ShibINI::boolean(tag))
     {
-        s+=site.m_name;
+        target=string(pfc->fIsSecurePort ? "https://" : "http://") + hostname + target;
     }
     else
     {
-        GetServerVariable(pfc,"SERVER_NAME",buf);
-        s+=buf;
+        GetServerVariable(pfc,"SERVER_NAME",url);
+        target=string(pfc->fIsSecurePort ? "https://" : "http://") + static_cast<char*>(url) + target;
     }
-
-    GetServerVariable(pfc,"SERVER_PORT",buf,10);
-    if (buf!=(pfc->fIsSecurePort ? "443" : "80"))
-        s=s + ':' + static_cast<char*>(buf);
-
-    GetHeader(pn,pfc,"url",buf,256,false);
-    s+=buf;
-
-    return s;
 }
 
-string get_shire_location(settings_t& site, const char* target)
+string get_shire_location(const char* application_id, const char* target)
 {
     string shireURL;
-    if (g_Config->getINI().get_tag(site.m_name,"shireURL",true,&shireURL) && !shireURL.empty())
+    if (g_Config->getINI().get_tag(application_id,"shireURL",true,&shireURL) && !shireURL.empty())
     {
         if (shireURL[0]!='/')
             return shireURL;
@@ -476,35 +438,27 @@ extern "C" DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificat
             return WriteClientError(pfc,"IIS site instance appears to be invalid.");
 
         // Match site instance to site settings.
-        if (site_id>g_Sites.size() || g_Sites[site_id-1].m_name.length()==0)
+        if (site_id>g_Sites.size() || g_Sites[site_id-1].length()==0)
             return SF_STATUS_REQ_NEXT_NOTIFICATION;
-        settings_t& site=g_Sites[site_id-1];
-
-        string target_url=get_target(pfc,pn,site);
-        string shire_url=get_shire_location(site,target_url.c_str());
+        string& site=g_Sites[site_id-1];
+        
+        string application_id;
+        string target_url;
+        get_target_and_appid(pfc,pn,site.c_str(),target_url,application_id);
+        string shire_url=get_shire_location(application_id.c_str(),target_url.c_str());
 
         // If the user is accessing the SHIRE acceptance point, pass it on.
         if (target_url.find(shire_url)!=string::npos)
             return SF_STATUS_REQ_NEXT_NOTIFICATION;
 
-        // Get the url request and scan for the must-contain string.
-        if (!site.m_mustContain.empty())
-        {
-            char* upcased=new char[target_url.length()+1];
-            strcpy(upcased,target_url.c_str());
-            _strupr(upcased);
-            for (vector<string>::const_iterator index=site.m_mustContain.begin(); index!=site.m_mustContain.end(); index++)
-                if (strstr(upcased,index->c_str()))
-                    break;
-            delete[] upcased;
-            if (index==site.m_mustContain.end())
-                return SF_STATUS_REQ_NEXT_NOTIFICATION;
-        }
+        // Now check the policy for this application.
+        string tag;
+        ShibINI& ini=g_Config->getINI();
+        if (!ini.get_tag(application_id,"requireSession",true,&tag) || !ShibINI::boolean(tag))
+            return SF_STATUS_REQ_NEXT_NOTIFICATION;
 
         // SSL content check.
-        ShibINI& ini=g_Config->getINI();
-        string tag;
-        if (ini.get_tag(site.m_name,"contentSSLOnly",true,&tag) && ShibINI::boolean(tag) && !pfc->fIsSecurePort)
+        if (ini.get_tag(application_id,"contentSSLOnly",true,&tag) && ShibINI::boolean(tag) && !pfc->fIsSecurePort)
         {
             return WriteClientError(pfc,
                 "This server is configured to deny non-SSL requests for secure resources. "
@@ -517,30 +471,30 @@ extern "C" DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificat
 
         // Set SHIRE policies.
         SHIREConfig config;
-        config.checkIPAddress = (ini.get_tag(site.m_name,"checkIPAddress",true,&tag) && ShibINI::boolean(tag));
+        config.checkIPAddress = (ini.get_tag(application_id,"checkIPAddress",true,&tag) && ShibINI::boolean(tag));
         config.lifetime=config.timeout=0;
         tag.erase();
-        if (ini.get_tag(site.m_name, "authLifetime", true, &tag))
+        if (ini.get_tag(application_id, "authLifetime", true, &tag))
             config.lifetime=strtoul(tag.c_str(),NULL,10);
         tag.erase();
-        if (ini.get_tag(site.m_name, "authTimeout", true, &tag))
+        if (ini.get_tag(application_id, "authTimeout", true, &tag))
             config.timeout=strtoul(tag.c_str(),NULL,10);
 
         // Pull the config data we need to handle the various possible conditions.
         string shib_cookie;
-        if (!ini.get_tag(site.m_name, "cookieName", true, &shib_cookie))
+        if (!ini.get_tag(application_id, "cookieName", true, &shib_cookie))
             return WriteClientError(pfc,"The cookieName configuration setting is missing, check configuration.");
     
         string wayfLocation;
-        if (!ini.get_tag(site.m_name, "wayfURL", true, &wayfLocation))
+        if (!ini.get_tag(application_id, "wayfURL", true, &wayfLocation))
             return WriteClientError(pfc,"The wayfURL configuration setting is missing, check configuration.");
     
         string shireError;
-        if (!ini.get_tag(site.m_name, "shireError", true, &shireError))
+        if (!ini.get_tag(application_id, "shireError", true, &shireError))
             return WriteClientError(pfc,"The shireError configuration setting is missing, check configuration.");
 
         string accessError;
-        if (!ini.get_tag(site.m_name, "accessError", true, &shireError))
+        if (!ini.get_tag(application_id, "accessError", true, &shireError))
             return WriteClientError(pfc,"The accessError configuration setting is missing, check configuration.");
         
         // Get an RPC handle and build the SHIRE object.
@@ -550,7 +504,7 @@ extern "C" DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificat
             rpc_handle = new RPCHandle(shib_target_sockname(), SHIBRPC_PROG, SHIBRPC_VERS_1);
             rpc_handle_key->setData(rpc_handle);
         }
-        SHIRE shire(rpc_handle, config, shire_url);
+        SHIRE shire(rpc_handle, config, shire_url.c_str());
 
         // Check for authentication cookie.
         const char* session_id=NULL;
@@ -575,16 +529,16 @@ extern "C" DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificat
         // Make sure this session is still valid.
         RPCError* status = NULL;
         ShibMLP markupProcessor;
-        bool has_tag = ini.get_tag(site.m_name, "supportContact", true, &tag);
+        bool has_tag = ini.get_tag(application_id, "supportContact", true, &tag);
         markupProcessor.insert("supportContact", has_tag ? tag : "");
-        has_tag = ini.get_tag(site.m_name, "logoLocation", true, &tag);
+        has_tag = ini.get_tag(application_id, "logoLocation", true, &tag);
         markupProcessor.insert("logoLocation", has_tag ? tag : "");
         markupProcessor.insert("requestURL", target_url);
     
         dynabuf abuf(16);
         GetServerVariable(pfc,"REMOTE_ADDR",abuf,16);
         try {
-            status = shire.sessionIsValid(session_id, abuf, target_url.c_str());
+            status = shire.sessionIsValid(session_id, abuf, application_id.c_str());
         }
         catch (ShibTargetException &e) {
             markupProcessor.insert("errorType", "SHIRE Processing Error");
@@ -628,11 +582,11 @@ extern "C" DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificat
         // Get the attributes.
         vector<SAMLAssertion*> assertions;
         SAMLAuthenticationStatement* sso_statement=NULL;
-        status = rm.getAssertions(session_id, buf, target_url.c_str(), assertions, &sso_statement);
+        status = rm.getAssertions(session_id, buf, application_id.c_str(), assertions, &sso_statement);
     
         if (status->isError()) {
             string rmError;
-            if (!ini.get_tag(site.m_name, "rmError", true, &shireError))
+            if (!ini.get_tag(application_id, "rmError", true, &shireError))
                 return WriteClientError(pfc,"The rmError configuration setting is missing, check configuration.");
     
             markupProcessor.insert(*status);
@@ -650,7 +604,7 @@ extern "C" DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificat
         }
 
         // Get the AAP providers, which contain the attribute policy info.
-        Iterator<IAAP*> provs=ShibConfig::getConfig().getAAPProviders();
+        Iterator<IAAP*> provs=g_Config->getAAPProviders();
     
         // Clear out the list of mapped attributes
         while (provs.hasNext())
@@ -685,8 +639,11 @@ extern "C" DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificat
         pn->SetHeader(pfc,"Shib-Origin-Site:","");
         pn->SetHeader(pfc,"Shib-Authentication-Method:","");
 
+        pn->SetHeader(pfc,"Shib-Application-ID:","");
+        pn->SetHeader(pfc,"Shib-Application-ID:",const_cast<char*>(application_id.c_str()));
+
         // Maybe export the assertion.
-        if (ini.get_tag(site.m_name,"exportAssertion",true,&tag) && ShibINI::boolean(tag))
+        if (ini.get_tag(application_id,"exportAssertion",true,&tag) && ShibINI::boolean(tag))
         {
             string assertion;
             RM::serialize(*(assertions[0]), assertion);
@@ -698,50 +655,54 @@ extern "C" DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificat
         
         if (sso_statement)
         {
-            auto_ptr<char> os(XMLString::transcode(sso_statement->getSubject()->getNameQualifier()));
-            auto_ptr<char> am(XMLString::transcode(sso_statement->getAuthMethod()));
-            pn->SetHeader(pfc,"Shib-Origin-Site:", os.get());
-            pn->SetHeader(pfc,"Shib-Authentication-Method:", am.get());
+            auto_ptr_char os(sso_statement->getSubject()->getNameQualifier());
+            auto_ptr_char am(sso_statement->getAuthMethod());
+            pn->SetHeader(pfc,"Shib-Origin-Site:", const_cast<char*>(os.get()));
+            pn->SetHeader(pfc,"Shib-Authentication-Method:", const_cast<char*>(am.get()));
         }
 
-        // Export the attributes. Only supports a single statement.
-        Iterator<SAMLAttribute*> j = assertions.size()==1 ? RM::getAttributes(*(assertions[0])) : EMPTY(SAMLAttribute*);
-        while (j.hasNext())
-        {
-            SAMLAttribute* attr=j.next();
-    
-            // Are we supposed to export it?
-            const char* hname=NULL;
-            AAP wrapper(attr->getName(),attr->getNamespace());
-            if (!wrapper.fail())
-                hname=wrapper->getHeader();
-            if (hname)
-            {
-                Iterator<string> vals=attr->getSingleByteValues();
-                if (!strcmp(hname,"REMOTE_USER") && vals.hasNext())
-                {
-                    char* principal=const_cast<char*>(vals.next().c_str());
-                    pn->SetHeader(pfc,"remote-user:",principal);
-                    pfc->pFilterContext=pfc->AllocMem(pfc,strlen(principal)+1,0);
-                    if (pfc->pFilterContext)
-                        strcpy(static_cast<char*>(pfc->pFilterContext),principal);
-                }    
-                else
-                {
-                    string header;
-                    for (int it = 0; vals.hasNext(); it++) {
-                        string value = vals.next();
-                        for (string::size_type pos = value.find_first_of(";", string::size_type(0)); pos != string::npos; pos = value.find_first_of(";", pos)) {
-                            value.insert(pos, "\\");
-                            pos += 2;
-                        }
-                        if (it == 0)
-                            header=value;
-                        else
-                            header=header + ';' + value;
+        // Export the attributes.
+        Iterator<SAMLAssertion*> a_iter(assertions);
+        while (a_iter.hasNext()) {
+            SAMLAssertion* assert=a_iter.next();
+            Iterator<SAMLStatement*> statements=assert->getStatements();
+            while (statements.hasNext()) {
+                SAMLAttributeStatement* astate=dynamic_cast<SAMLAttributeStatement*>(statements.next());
+                if (!astate)
+                    continue;
+                Iterator<SAMLAttribute*> attrs=astate->getAttributes();
+                while (attrs.hasNext()) {
+                    SAMLAttribute* attr=attrs.next();
+        
+                    // Are we supposed to export it?
+                    AAP wrapper(g_Config->getAAPProviders(),attr->getName(),attr->getNamespace());
+                    if (wrapper.fail())
+                        continue;
+                
+                    Iterator<string> vals=attr->getSingleByteValues();
+                    if (!strcmp(wrapper->getHeader(),"REMOTE_USER") && vals.hasNext()) {
+                        char* principal=const_cast<char*>(vals.next().c_str());
+                        pn->SetHeader(pfc,"remote-user:",principal);
+                        pfc->pFilterContext=pfc->AllocMem(pfc,strlen(principal)+1,0);
+                        if (pfc->pFilterContext)
+                            strcpy(static_cast<char*>(pfc->pFilterContext),principal);
                     }
-                    string hname2=string(hname) + ':';
-                    pn->SetHeader(pfc,const_cast<char*>(hname2.c_str()),const_cast<char*>(header.c_str()));
+                    else {
+                        string header;
+                        for (int it = 0; vals.hasNext(); it++) {
+                            string value = vals.next();
+                            for (string::size_type pos = value.find_first_of(";", string::size_type(0)); pos != string::npos; pos = value.find_first_of(";", pos)) {
+                                value.insert(pos, "\\");
+                                pos += 2;
+                            }
+                            if (it == 0)
+                                header=value;
+                            else
+                                header=header + ';' + value;
+                        }
+                        string hname2=string(wrapper->getHeader()) + ':';
+                        pn->SetHeader(pfc,const_cast<char*>(hname2.c_str()),const_cast<char*>(header.c_str()));
+                       }
                 }
             }
         }
@@ -772,37 +733,35 @@ extern "C" DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificat
     return WriteClientError(pfc,"Server reached unreachable code!");
 }
 
-string get_target(LPEXTENSION_CONTROL_BLOCK lpECB, settings_t& site)
+void get_target_and_appid(LPEXTENSION_CONTROL_BLOCK lpECB, const char* hostname, string& target, string& appid)
 {
-    string s;
-    dynabuf buf(256);
-    GetServerVariable(lpECB,"HTTPS",buf);
-    bool SSL=(buf=="on");
-    if (SSL)
-        s="https://";
-    else
-        s="http://";
+    dynabuf ssl(5);
+    dynabuf port(10);
+    dynabuf url(256);
+    GetServerVariable(lpECB,"HTTPS",ssl,5);
+    GetServerVariable(lpECB,"SERVER_PORT",port,10);
+    GetServerVariable(lpECB,"URL",url,255);
+    bool SSL=(ssl=="on");
+    
+    // First get the appid using the normalized hostname.
+    ApplicationMapper mapper;
+    appid = mapper->getApplicationFromParsedURL((SSL ? "https" : "http"), hostname, atoi(port), url);
+
+    target=static_cast<char*>(url);
+    if (port!=(SSL ? "443" : "80"))
+        target = ':' + static_cast<char*>(port) + target;
 
-    // We use the "normalizeRequest" tag to decide how to obtain the server's name.
+    // For the target, we use the "normalizeRequest" tag to decide how to set the server's name.
     string tag;
-    if (g_Config->getINI().get_tag(site.m_name,"normalizeRequest",true,&tag) && ShibINI::boolean(tag))
+    if (g_Config->getINI().get_tag(appid,"normalizeRequest",true,&tag) && ShibINI::boolean(tag))
     {
-        s+=site.m_name;
+        target=string(SSL ? "https://" : "http://") + hostname + target;
     }
     else
     {
-        GetServerVariable(lpECB,"SERVER_NAME",buf);
-        s+=buf;
+        GetServerVariable(lpECB,"SERVER_NAME",url);
+        target=string(SSL ? "https://" : "http://") + static_cast<char*>(url) + target;
     }
-
-    GetServerVariable(lpECB,"SERVER_PORT",buf,10);
-    if (buf!=(SSL ? "443" : "80"))
-        s=s + ':' + static_cast<char*>(buf);
-
-    GetServerVariable(lpECB,"URL",buf,255);
-    s+=buf;
-
-    return s;
 }
 
 DWORD WriteClientError(LPEXTENSION_CONTROL_BLOCK lpECB, const char* msg)
@@ -855,40 +814,42 @@ extern "C" DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB)
             return WriteClientError(lpECB,"IIS site instance appears to be invalid.");
 
         // Match site instance to site settings.
-        if (site_id>g_Sites.size() || g_Sites[site_id-1].m_name.length()==0)
+        if (site_id>g_Sites.size() || g_Sites[site_id-1].length()==0)
             return WriteClientError(lpECB,"Shibboleth filter not configured for this web site.");
-        settings_t& site=g_Sites[site_id-1];
+        string& site=g_Sites[site_id-1];
+
+        string target_url,application_id;
+        get_target_and_appid(lpECB,site.c_str(),target_url,application_id);
 
-        if (!ini.get_tag(site.m_name, "shireError", true, &shireError))
+        if (!ini.get_tag(application_id, "shireError", true, &shireError))
             return WriteClientError(lpECB,"The shireError configuration setting is missing, check configuration.");
 
-        string target_url=get_target(lpECB,site);
-        string shire_url = get_shire_location(site,target_url.c_str());
+        string shire_url = target_url;
 
         // Set SHIRE policies.
         SHIREConfig config;
         string tag;
-        config.checkIPAddress = (ini.get_tag(site.m_name,"checkIPAddress",true,&tag) && ShibINI::boolean(tag));
+        config.checkIPAddress = (ini.get_tag(application_id,"checkIPAddress",true,&tag) && ShibINI::boolean(tag));
         config.lifetime=config.timeout=0;
         tag.erase();
-        if (ini.get_tag(site.m_name, "authLifetime", true, &tag))
+        if (ini.get_tag(application_id, "authLifetime", true, &tag))
             config.lifetime=strtoul(tag.c_str(),NULL,10);
         tag.erase();
-        if (ini.get_tag(site.m_name, "authTimeout", true, &tag))
+        if (ini.get_tag(application_id, "authTimeout", true, &tag))
             config.timeout=strtoul(tag.c_str(),NULL,10);
 
         // Pull the config data we need to handle the various possible conditions.
         string shib_cookie;
-        if (!ini.get_tag(site.m_name, "cookieName", true, &shib_cookie))
+        if (!ini.get_tag(application_id, "cookieName", true, &shib_cookie))
             return WriteClientError(lpECB,"The cookieName configuration setting is missing, check configuration.");
     
         string wayfLocation;
-        if (!ini.get_tag(site.m_name, "wayfURL", true, &wayfLocation))
+        if (!ini.get_tag(application_id, "wayfURL", true, &wayfLocation))
             return WriteClientError(lpECB,"The wayfURL configuration setting is missing, check configuration.");
     
-        bool has_tag = ini.get_tag(site.m_name, "supportContact", true, &tag);
+        bool has_tag = ini.get_tag(application_id, "supportContact", true, &tag);
         markupProcessor.insert("supportContact", has_tag ? tag : "");
-        has_tag = ini.get_tag(site.m_name, "logoLocation", true, &tag);
+        has_tag = ini.get_tag(application_id, "logoLocation", true, &tag);
         markupProcessor.insert("logoLocation", has_tag ? tag : "");
         markupProcessor.insert("requestURL", target_url.c_str());
   
@@ -902,7 +863,7 @@ extern "C" DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB)
         SHIRE shire(rpc_handle, config, shire_url.c_str());
 
         // Process SHIRE POST
-        if (ini.get_tag(site.m_name, "shireSSLOnly", true, &tag) && ShibINI::boolean(tag))
+        if (ini.get_tag(application_id, "shireSSLOnly", true, &tag) && ShibINI::boolean(tag))
         {
             // Make sure this is SSL, if it should be.
             GetServerVariable(lpECB,"HTTPS",buf,10);
@@ -943,7 +904,7 @@ extern "C" DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB)
 
         // Process the post.
         string cookie;
-        RPCError* status = shire.sessionCreate(post,buf,cookie);
+        RPCError* status = shire.sessionCreate(post,buf,application_id.c_str(),cookie);
     
         if (status->isError()) {
             if (status->isRetryable()) {
index 062ad60..f8340c7 100644 (file)
@@ -36,21 +36,6 @@ using namespace shibtarget;
 namespace {
     ThreadKey* rpc_handle_key = NULL;
     ShibTargetConfig* g_Config = NULL;
-
-       map<string,string> g_mapAttribNameToHeader;
-    map<string,string> g_mapAttribRuleToHeader;
-}
-
-extern "C" const char*
-ap_set_attribute_mapping(cmd_parms* parms, void*, const char* attrName,
-                            const char* headerName, const char* ruleName)
-{
-    ap_log_error(APLOG_MARK,APLOG_WARNING|APLOG_NOERRNO,parms->server,
-                "ShibMapAttribute command has been deprecated, please transfer this information to your AAP file(s).");
-    g_mapAttribNameToHeader[attrName]=headerName;
-    if (ruleName)
-        g_mapAttribRuleToHeader[ruleName]=headerName;
-    return NULL;
 }
 
 extern "C" module MODULE_VAR_EXPORT shibrm_module;
@@ -95,9 +80,6 @@ typedef const char* (*config_fn_t)(void);
 // SHIBRM Module commands
 
 static command_rec shibrm_cmds[] = {
-  {"ShibMapAttribute", (config_fn_t)ap_set_attribute_mapping, NULL,
-   RSRC_CONF, TAKE23, "Define request header name and 'require' alias for an attribute."},
-
   {"AuthGroupFile", (config_fn_t)ap_set_file_slot,
    (void *) XtOffsetOf (shibrm_dir_config, szAuthGrpFile),
    OR_AUTHCFG, TAKE1, "text file containing group names and member user IDs"},
@@ -217,25 +199,14 @@ static int shibrm_error_page(request_rec* r, const char* filename, ShibMLP& mlp)
   return DONE;
 }
 
-// return the "normalized" target URL
-static const char* get_target(request_rec* r, const char* target)
+static const char* get_application_id(request_rec* r)
 {
-  string tag;
-  if ((g_Config->getINI()).get_tag (ap_get_server_name(r), "normalizeRequest", true, &tag))
-  {
-    if (ShibINI::boolean (tag))
-    {
-        const char* colon=strchr(target,':');
-        const char* slash=strchr(colon+3,'/');
-        const char* second_colon=strchr(colon+3,':');
-        return ap_pstrcat(r->pool,ap_pstrndup(r->pool,target,colon+3-target),
-                         ap_get_server_name(r),
-                         (second_colon && second_colon < slash) ?
-                         second_colon : slash,
-                         NULL);
-    }
-  }
-  return target;
+    ApplicationMapper mapper;
+    return ap_pstrdup(r->pool,
+        mapper->getApplicationFromParsedURL(
+            ap_http_method(r), ap_get_server_name(r), ap_get_server_port(r), r->unparsed_uri
+            )
+       );
 }
 
 extern "C" int shibrm_check_auth(request_rec* r)
@@ -256,28 +227,27 @@ extern "C" int shibrm_check_auth(request_rec* r)
     saml::NDC ndc(threadid.str().c_str());
 
     ShibINI& ini = g_Config->getINI();
-    const char* serverName = ap_get_server_name(r);
 
-    // Ok, this is a SHIB target; grab the cookie
+    // This will always be normalized, because Apache uses ap_get_server_name in this API call.
+    const char* targeturl=ap_construct_url(r->pool,r->unparsed_uri,r);
+    
+    // Map request to application ID, which is the key for config lookup.
+    const char* application_id=get_application_id(r);
 
+    // Ok, this is a SHIB target; grab the cookie
     string shib_cookie;
-    if (!ini.get_tag(serverName, "cookieName", true, &shib_cookie)) {
+    if (!ini.get_tag(application_id, "cookieName", true, &shib_cookie)) {
       ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
-                   "shibrm_check_user: no cookieName configuration for %s",
-                   serverName);
+                   "shibrm_check_user: no cookieName configuration for %s", application_id);
       return SERVER_ERROR;
     }
 
-    const char* targeturl=get_target(r,ap_construct_url(r->pool,r->unparsed_uri,r));
-
     const char* session_id=NULL;
     const char* cookies=ap_table_get(r->headers_in,"Cookie");
     if (!cookies || !(session_id=strstr(cookies,shib_cookie.c_str())))
     {
       // No cookie???  Must be a server error!
-      ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,
-                   "shibrm_check_auth() no cookie found");
-
+      ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"shibrm_check_auth() no cookie found");
       return SERVER_ERROR;
     }
 
@@ -291,14 +261,14 @@ extern "C" int shibrm_check_auth(request_rec* r)
 
     ShibMLP markupProcessor;
     string tag;
-    bool has_tag = ini.get_tag(serverName, "supportContact", true, &tag);
+    bool has_tag = ini.get_tag(application_id, "supportContact", true, &tag);
     markupProcessor.insert("supportContact", has_tag ? tag : "");
-    has_tag = ini.get_tag(serverName, "logoLocation", true, &tag);
+    has_tag = ini.get_tag(application_id, "logoLocation", true, &tag);
     markupProcessor.insert("logoLocation", has_tag ? tag : "");
     markupProcessor.insert("requestURL", targeturl);
 
     // Now grab the attributes...
-    has_tag = ini.get_tag (serverName, "checkIPAddress", true, &tag);
+    has_tag = ini.get_tag (application_id, "checkIPAddress", true, &tag);
     dc->config.checkIPAddress = (has_tag ? ShibINI::boolean (tag) : false);
 
     // Get an RPC handle and build the RM object.
@@ -312,7 +282,7 @@ extern "C" int shibrm_check_auth(request_rec* r)
 
     vector<SAMLAssertion*> assertions;
     SAMLAuthenticationStatement* sso_statement=NULL;
-    RPCError* status = rm.getAssertions(session_id, r->connection->remote_ip, targeturl, assertions, &sso_statement);
+    RPCError* status = rm.getAssertions(session_id, r->connection->remote_ip, application_id, assertions, &sso_statement);
 
     if (status->isError()) {
       ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,
@@ -320,10 +290,9 @@ extern "C" int shibrm_check_auth(request_rec* r)
                    status->getText());
 
       string rmError;
-      if (!ini.get_tag(serverName, "rmError", true, &rmError)) {
+      if (!ini.get_tag(application_id, "rmError", true, &rmError)) {
         ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
-                     "shibrm_check_auth: no rmError configuration for %s",
-                     serverName);
+                     "shibrm_check_auth: no rmError configuration for %s", application_id);
         delete status;
         return SERVER_ERROR;   
       }
@@ -334,10 +303,9 @@ extern "C" int shibrm_check_auth(request_rec* r)
     delete status;
 
     string rmError;
-    if (!ini.get_tag(serverName, "accessError", true, &rmError)) {
+    if (!ini.get_tag(application_id, "accessError", true, &rmError)) {
         ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
-           "shibrm_check_auth: no accessError configuration for %s",
-            serverName);
+           "shibrm_check_auth: no accessError configuration for %s", application_id);
 
         delete status;
         for (int k = 0; k < assertions.size(); k++)
@@ -346,19 +314,8 @@ extern "C" int shibrm_check_auth(request_rec* r)
         return SERVER_ERROR;  
     }
 
-    // Only allow a single assertion...
-    if (assertions.size() > 1) {
-        ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,
-                   "shibrm_check_auth() found %d assertions (only handle 1 currently)",
-                   assertions.size());
-        for (int k = 0; k < assertions.size(); k++)
-          delete assertions[k];
-        delete sso_statement;
-        return shibrm_error_page (r, rmError.c_str(), markupProcessor);
-    }
-
     // Get the AAP providers, which contain the attribute policy info.
-    Iterator<IAAP*> provs=ShibConfig::getConfig().getAAPProviders();
+    Iterator<IAAP*> provs=g_Config->getAAPProviders();
 
     // Clear out the list of mapped attributes
     while (provs.hasNext())
@@ -387,9 +344,9 @@ extern "C" int shibrm_check_auth(request_rec* r)
     }
     provs.reset();
     
-    // Maybe export the assertion.
+    // Maybe export the first assertion.
     ap_table_unset(r->headers_in,"Shib-Attributes");
-    if (dc->bExportAssertion==1 && assertions.size()==1) {
+    if (dc->bExportAssertion==1 && assertions.size()) {
         string assertion;
         RM::serialize(*(assertions[0]), assertion);
         ap_table_set(r->headers_in,"Shib-Attributes", assertion.c_str());
@@ -400,53 +357,49 @@ extern "C" int shibrm_check_auth(request_rec* r)
     ap_table_unset(r->headers_in,"Shib-Authentication-Method");
     if (sso_statement)
     {
-        auto_ptr<char> os(XMLString::transcode(sso_statement->getSubject()->getNameQualifier()));
-        auto_ptr<char> am(XMLString::transcode(sso_statement->getAuthMethod()));
+        auto_ptr_char os(sso_statement->getSubject()->getNameQualifier());
+        auto_ptr_char am(sso_statement->getAuthMethod());
         ap_table_set(r->headers_in,"Shib-Origin-Site", os.get());
         ap_table_set(r->headers_in,"Shib-Authentication-Method", am.get());
     }
-
-    // Export the attributes. Only supports a single statement.
-    Iterator<SAMLAttribute*> j = assertions.size()==1 ? RM::getAttributes(*(assertions[0])) : EMPTY(SAMLAttribute*);
-    while (j.hasNext())
-    {
-        SAMLAttribute* attr=j.next();
-
-        // Are we supposed to export it?
-        const char* hname=NULL;
-        AAP wrapper(attr->getName(),attr->getNamespace());
-        if (!wrapper.fail())
-            hname=wrapper->getHeader();
-        if (!hname)
-        {
-            auto_ptr<char> tname(XMLString::transcode(attr->getName()));
-               map<string,string>::const_iterator iname=g_mapAttribNameToHeader.find(tname.get());
-               if (iname!=g_mapAttribNameToHeader.end())
-                       hname=iname->second.c_str();
-        }
-        if (hname)
-        {
-            Iterator<string> vals=attr->getSingleByteValues();
-            if (!strcmp(hname,"REMOTE_USER") && vals.hasNext())
-                r->connection->user=ap_pstrdup(r->connection->pool,vals.next().c_str());
-            else
-            {
-                char* header = ap_pstrdup(r->pool, "");
-                for (int it = 0; vals.hasNext(); it++) {
-                    string value = vals.next();
-                    for (string::size_type pos = value.find_first_of(";", string::size_type(0)); pos != string::npos; pos = value.find_first_of(";", pos)) {
-                       value.insert(pos, "\\");
-                       pos += 2;
-                    }
-                    if (it == 0) {
-                        header=ap_pstrcat(r->pool, value.c_str(), NULL);
-                    }
-                    else {
-                        header=ap_pstrcat(r->pool, header, ";", value.c_str(), NULL);
+    
+    ap_table_unset(r->headers_in,"Shib-Application-ID");
+    ap_table_set(r->headers_in,"Shib-Application-ID",application_id);
+
+    // Export the attributes.
+    Iterator<SAMLAssertion*> a_iter(assertions);
+    while (a_iter.hasNext()) {
+        SAMLAssertion* assert=a_iter.next();
+        Iterator<SAMLStatement*> statements=assert->getStatements();
+        while (statements.hasNext()) {
+            SAMLAttributeStatement* astate=dynamic_cast<SAMLAttributeStatement*>(statements.next());
+            if (!astate)
+                continue;
+            Iterator<SAMLAttribute*> attrs=astate->getAttributes();
+            while (attrs.hasNext()) {
+                SAMLAttribute* attr=attrs.next();
+        
+                // Are we supposed to export it?
+                AAP wrapper(provs,attr->getName(),attr->getNamespace());
+                if (wrapper.fail())
+                    continue;
+                
+                Iterator<string> vals=attr->getSingleByteValues();
+                if (!strcmp(wrapper->getHeader(),"REMOTE_USER") && vals.hasNext())
+                    r->connection->user=ap_pstrdup(r->connection->pool,vals.next().c_str());
+                else {
+                    char* header = ap_pstrdup(r->pool, "");
+                    for (int it = 0; vals.hasNext(); it++) {
+                        string value = vals.next();
+                        for (string::size_type pos = value.find_first_of(";", string::size_type(0)); pos != string::npos; pos = value.find_first_of(";", pos)) {
+                               value.insert(pos, "\\");
+                               pos += 2;
+                        }
+                        header=ap_pstrcat(r->pool, header, (it ? ";" : ""), value.c_str(), NULL);
                     }
-                }
-                ap_table_setn(r->headers_in, hname, header);
-           }
+                    ap_table_setn(r->headers_in, wrapper->getHeader(), header);
+                   }
+            }
         }
     }
 
@@ -508,7 +461,7 @@ extern "C" int shibrm_check_auth(request_rec* r)
                     }
                     catch (XMLException& ex)
                     {
-                        auto_ptr<char> tmp(XMLString::transcode(ex.getMessage()));
+                        auto_ptr_char tmp(ex.getMessage());
                         ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,
                                         "shibrm_check_auth caught exception while parsing regular expression (%s): %s",w,tmp.get());
                     }
@@ -544,112 +497,94 @@ extern "C" int shibrm_check_auth(request_rec* r)
         }
         else
         {
-            const char* hname=NULL;
-            AAP wrapper(w);
-            if (!wrapper.fail())
-                hname=wrapper->getHeader();
-            if (!hname)
-            {
-                map<string,string>::const_iterator fallback=g_mapAttribRuleToHeader.find(w);
-                if (fallback!=g_mapAttribRuleToHeader.end())
-                    hname=fallback->second.c_str();
-            }
-            
-            if (!hname) {
+            AAP wrapper(provs,w);
+            if (wrapper.fail()) {
                 ap_log_rerror(APLOG_MARK,APLOG_WARNING|APLOG_NOERRNO,r,
                                 "shibrm_check_auth() didn't recognize require rule: %s\n",w);
+                continue;
             }
-            else
-            {
-                bool regexp=false;
-                const char* vals=ap_table_get(r->headers_in,hname);
-                while (*t && vals)
-                {
-                    w=ap_getword_conf(r->pool,&t);
-                    if (*w=='~')
-                    {
-                        regexp=true;
-                        continue;
-                    }
 
-                    try
-                    {
-                        auto_ptr<RegularExpression> re;
-                        if (regexp)
-                        {
-                            delete re.release();
-                            auto_ptr<XMLCh> trans(fromUTF8(w));
-                            auto_ptr<RegularExpression> temp(new RegularExpression(trans.get()));
-                            re=temp;
-                        }
-                        
-                        string vals_str(vals);
-                        int j = 0;
-                        for (int i = 0;  i < vals_str.length();  i++)
-                        {
-                            if (vals_str.at(i) == ';') 
-                            {
-                                if (i == 0) {
-                                    ap_log_rerror(APLOG_MARK,APLOG_WARNING|APLOG_NOERRNO,r,
-                                                    "shibrm_check_auth() invalid header encoding %s: starts with semicolon", vals);
-                                    return SERVER_ERROR;
-                                }
-        
-                                if (vals_str.at(i-1) == '\\') {
-                                    vals_str.erase(i-1, 1);
-                                    i--;
-                                    continue;
-                                }
-        
-                                string val = vals_str.substr(j, i-j);
-                                j = i+1;
-                                if (regexp) {
-                                    auto_ptr<XMLCh> trans(fromUTF8(val.c_str()));
-                                    if (re->matches(trans.get())) {
-                                        ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
-                                                        "shibrm_check_auth() expecting %s, got %s: authorization granted", w, val.c_str());
-                                        return OK;
-                                    }
-                                }
-                                else if (val==w) {
+            bool regexp=false;
+            const char* vals=ap_table_get(r->headers_in,wrapper->getHeader());
+            while (*t && vals) {
+                w=ap_getword_conf(r->pool,&t);
+                if (*w=='~') {
+                    regexp=true;
+                    continue;
+                }
+
+                try {
+                    auto_ptr<RegularExpression> re;
+                    if (regexp) {
+                        delete re.release();
+                        auto_ptr<XMLCh> trans(fromUTF8(w));
+                        auto_ptr<RegularExpression> temp(new RegularExpression(trans.get()));
+                        re=temp;
+                    }
+                    
+                    string vals_str(vals);
+                    int j = 0;
+                    for (int i = 0;  i < vals_str.length();  i++) {
+                        if (vals_str.at(i) == ';') {
+                            if (i == 0) {
+                                ap_log_rerror(APLOG_MARK,APLOG_WARNING|APLOG_NOERRNO,r,
+                                                "shibrm_check_auth() invalid header encoding %s: starts with semicolon", vals);
+                                return SERVER_ERROR;
+                            }
+    
+                            if (vals_str.at(i-1) == '\\') {
+                                vals_str.erase(i-1, 1);
+                                i--;
+                                continue;
+                            }
+    
+                            string val = vals_str.substr(j, i-j);
+                            j = i+1;
+                            if (regexp) {
+                                auto_ptr<XMLCh> trans(fromUTF8(val.c_str()));
+                                if (re->matches(trans.get())) {
                                     ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
                                                     "shibrm_check_auth() expecting %s, got %s: authorization granted", w, val.c_str());
                                     return OK;
                                 }
-                                else {
-                                    ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
-                                                    "shibrm_check_auth() expecting %s, got %s: authorization not granted", w, val.c_str());
-                                }
                             }
-                        }
-        
-                        string val = vals_str.substr(j, vals_str.length()-j);
-                        if (regexp) {
-                            auto_ptr<XMLCh> trans(fromUTF8(val.c_str()));
-                            if (re->matches(trans.get())) {
+                            else if (val==w) {
                                 ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
                                                 "shibrm_check_auth() expecting %s, got %s: authorization granted", w, val.c_str());
                                 return OK;
                             }
+                            else {
+                                ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
+                                                "shibrm_check_auth() expecting %s, got %s: authorization not granted", w, val.c_str());
+                            }
                         }
-                        else if (val==w) {
+                    }
+    
+                    string val = vals_str.substr(j, vals_str.length()-j);
+                    if (regexp) {
+                        auto_ptr<XMLCh> trans(fromUTF8(val.c_str()));
+                        if (re->matches(trans.get())) {
                             ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
                                             "shibrm_check_auth() expecting %s, got %s: authorization granted", w, val.c_str());
                             return OK;
                         }
-                        else {
-                            ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
-                                            "shibrm_check_auth() expecting %s, got %s: authorization not granted", w, val.c_str());
-                        }
                     }
-                    catch (XMLException& ex)
-                    {
-                        auto_ptr<char> tmp(XMLString::transcode(ex.getMessage()));
-                        ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,
-                                        "shibrm_check_auth caught exception while parsing regular expression (%s): %s",w,tmp.get());
+                    else if (val==w) {
+                        ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
+                                        "shibrm_check_auth() expecting %s, got %s: authorization granted", w, val.c_str());
+                        return OK;
+                    }
+                    else {
+                        ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
+                                        "shibrm_check_auth() expecting %s, got %s: authorization not granted", w, val.c_str());
                     }
                 }
-           }
+                catch (XMLException& ex) {
+                    auto_ptr<char> tmp(XMLString::transcode(ex.getMessage()));
+                    ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,
+                                    "shibrm_check_auth caught exception while parsing regular expression (%s): %s",w,tmp.get());
+                }
+            }
        }
     }
 
index 1c8e08f..615f1f6 100644 (file)
@@ -198,49 +198,35 @@ static char* url_encode(request_rec* r, const char* s)
     return ret;
 }
 
-static const char* get_shire_location(request_rec* r, const char* target, bool encode)
+static const char* get_application_id(request_rec* r)
+{
+    ApplicationMapper mapper;
+    return ap_pstrdup(r->pool,
+        mapper->getApplicationFromParsedURL(
+            ap_http_method(r), ap_get_server_name(r), ap_get_server_port(r), r->unparsed_uri
+            )
+       );
+}
+
+static const char* get_shire_location(request_rec* r, const char* target, const char* application_id)
 {
-  ShibINI& ini = g_Config->getINI();
   string shire_location;
+  ShibINI& ini = g_Config->getINI();
 
-  if (g_szSHIREURL)
-    shire_location = g_szSHIREURL;
-  else if (! ini.get_tag (ap_get_server_name(r), "shireURL", true, &shire_location)) {
+  if (!ini.get_tag (application_id, "shireURL", true, &shire_location)) {
     ap_log_rerror(APLOG_MARK,APLOG_ERR,r,
-                 "shire_get_location() no shireURL configuration for %s",
-                 ap_get_server_name(r));
+                 "shire_get_location() no shireURL configuration for %s", application_id);
     return NULL;
   }
 
   const char* shire = shire_location.c_str();
 
-  if (*shire != '/') {
-    if (encode)
-      return url_encode(r,shire);
-    else
+  if (*shire != '/')
       return ap_pstrdup(r->pool,shire);
-    }    
-    const char* colon=strchr(target,':');
-    const char* slash=strchr(colon+3,'/');
-    if (encode)
-      return url_encode(r,ap_pstrcat(r->pool,
-                                    ap_pstrndup(r->pool,target,slash-target),
-                                    shire,NULL));
-    else
-      return ap_pstrcat(r->pool, ap_pstrndup(r->pool,target,slash-target),
-                       shire, NULL);
-}
-
-static bool is_shire_location(request_rec* r, const char* target)
-{
-  const char* shire = get_shire_location(r, target, false);
 
-  if (!shire) return false;
-
-  if (!strstr(target, shire))
-    return false;
-
-  return (!strcmp(target,shire));
+  const char* colon=strchr(target,':');
+  const char* slash=strchr(colon+3,'/');
+  return ap_pstrcat(r->pool, ap_pstrndup(r->pool,target,slash-target), shire, NULL);
 }
 
 static int shire_error_page(request_rec* r, const char* filename, ShibMLP& mlp)
@@ -265,9 +251,15 @@ extern "C" int shire_check_user(request_rec* r)
     shire_dir_config* dc=(shire_dir_config*)ap_get_module_config(r->per_dir_config,&shire_module);
 
     // This will always be normalized, because Apache uses ap_get_server_name in this API call.
-    char* targeturl=ap_construct_url(r->pool,r->unparsed_uri,r);
-
-    if (is_shire_location (r, targeturl)) {
+    const char* targeturl=ap_construct_url(r->pool,r->unparsed_uri,r);
+    
+    // Map request to application ID, which is the key for config lookup.
+    const char* application_id=get_application_id(r);
+    
+    // Get unescaped location of this application's assertion consumer service.
+    const char* unescaped_shire = get_shire_location(r, targeturl, application_id);
+    
+    if (strstr(targeturl,unescaped_shire)) {
       ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
            "shire_check_user: REQUEST FOR SHIRE!  Maybe you did not configure the SHIRE Handler?");
       return SERVER_ERROR;
@@ -298,8 +290,7 @@ extern "C" int shire_check_user(request_rec* r)
       // SSL check.
       if (dc->bSSLOnly==1 && strcmp(ap_http_method(r),"https"))
       {
-        ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,
-           "shire_check_user() blocked non-SSL access");
+        ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"shire_check_user() blocked non-SSL access");
         return SERVER_ERROR;
       }
     }
@@ -313,38 +304,29 @@ extern "C" int shire_check_user(request_rec* r)
     ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
                     "shire_check_user() Shib check for %s", targeturl);
 
-
-    const char * shire_location = get_shire_location(r,targeturl,true);
-    if (!shire_location)
-        return SERVER_ERROR;
-    string shire_url = get_shire_location(r,targeturl,false);
-
-    const char* serverName = ap_get_server_name(r);
+    
     string tag;
-    bool has_tag = ini.get_tag (serverName, "checkIPAddress", true, &tag);
+    bool has_tag = ini.get_tag (application_id, "checkIPAddress", true, &tag);
     dc->config.checkIPAddress = (has_tag ? ShibINI::boolean (tag) : false);
 
     string shib_cookie;
-    if (! ini.get_tag(serverName, "cookieName", true, &shib_cookie)) {
+    if (!ini.get_tag(application_id, "cookieName", true, &shib_cookie)) {
       ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
-                   "shire_check_user: no cookieName configuration for %s",
-                   serverName);
+                   "shire_check_user: no cookieName configuration for %s", application_id);
       return SERVER_ERROR;
     }
 
     string wayfLocation;
-    if (! ini.get_tag(serverName, "wayfURL", true, &wayfLocation)) {
+    if (!ini.get_tag(application_id, "wayfURL", true, &wayfLocation)) {
       ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
-                   "shire_check_user: no wayfURL configuration for %s",
-                   serverName);
+                   "shire_check_user: no wayfURL configuration for %s", application_id);
       return SERVER_ERROR;
     }
 
     string shireError;
-    if (! ini.get_tag(serverName, "shireError", true, &shireError)) {
+    if (!ini.get_tag(application_id, "shireError", true, &shireError)) {
       ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
-                   "shire_check_user: no shireError configuration for %s",
-                   serverName);
+                   "shire_check_user: no shireError configuration for %s", application_id);
       return SERVER_ERROR;
     }
     
@@ -355,7 +337,7 @@ extern "C" int shire_check_user(request_rec* r)
         rpc_handle = new RPCHandle(shib_target_sockname(), SHIBRPC_PROG, SHIBRPC_VERS_1);
         rpc_handle_key->setData(rpc_handle);
     }
-    SHIRE shire(rpc_handle, dc->config, shire_url);
+    SHIRE shire(rpc_handle, dc->config, unescaped_shire);
 
     // We're in charge, so check for cookie.
     const char* session_id=NULL;
@@ -383,7 +365,7 @@ extern "C" int shire_check_user(request_rec* r)
         ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
                      "shire_check_user() no cookie found -- redirecting to WAYF");
         char* wayf=ap_pstrcat(r->pool,wayfLocation.c_str(),
-                             "?shire=",shire_location,
+                             "?shire=",url_encode(r,unescaped_shire),
                              "&target=",url_encode(r,targeturl),NULL);
         ap_table_setn(r->headers_out,"Location",wayf);
         return REDIRECT;
@@ -392,14 +374,14 @@ extern "C" int shire_check_user(request_rec* r)
     // Make sure this session is still valid
     RPCError* status = NULL;
     ShibMLP markupProcessor;
-    has_tag = ini.get_tag(serverName, "supportContact", true, &tag);
+    has_tag = ini.get_tag(application_id, "supportContact", true, &tag);
     markupProcessor.insert("supportContact", has_tag ? tag : "");
-    has_tag = ini.get_tag(serverName, "logoLocation", true, &tag);
+    has_tag = ini.get_tag(application_id, "logoLocation", true, &tag);
     markupProcessor.insert("logoLocation", has_tag ? tag : "");
     markupProcessor.insert("requestURL", targeturl);
 
     try {
-        status = shire.sessionIsValid(session_id, r->connection->remote_ip,targeturl);
+        status = shire.sessionIsValid(session_id, r->connection->remote_ip,application_id);
     }
     catch (ShibTargetException &e) {
         ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_user(): %s", e.what());
@@ -425,7 +407,7 @@ extern "C" int shire_check_user(request_rec* r)
         if (status->isRetryable()) {
             // Oops, session is invalid.  Redirect to WAYF.
             char* wayf=ap_pstrcat(r->pool,wayfLocation.c_str(),
-                               "?shire=",shire_location,
+                               "?shire=",url_encode(r,unescaped_shire),
                                "&target=",url_encode(r,targeturl),NULL);
             ap_table_setn(r->headers_out,"Location",wayf);
 
@@ -441,8 +423,7 @@ extern "C" int shire_check_user(request_rec* r)
     }
     else {
         delete status;
-        ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
-                     "shire_check_user() success");
+        ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_user() success");
         return OK;
     }
 
@@ -461,46 +442,44 @@ extern "C" int shire_post_handler (request_rec* r)
 
   ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_post_handler() ENTER");
 
-  const char* targeturl=ap_construct_url(r->pool,r->unparsed_uri,r);
-  const char * shire_location = get_shire_location(r,targeturl,true);
-  if (!shire_location)
-      return SERVER_ERROR;
-  string shire_url = get_shire_location(r,targeturl,false);
+  // This will always be normalized, because Apache uses ap_get_server_name in this API call.
+  const char* targeturl = ap_construct_url(r->pool,r->unparsed_uri,r);
+   
+  // Map request to application ID, which is the key for config lookup.
+  const char* application_id = get_application_id(r);
+    
+  // The SHIRE URL is the current request URL, by definition...
+  const char* unescaped_shire = targeturl;
 
-  const char* serverName = ap_get_server_name(r);
   string tag;
-  bool has_tag = ini.get_tag(serverName, "checkIPAddress", true, &tag);
+  bool has_tag = ini.get_tag(application_id, "checkIPAddress", true, &tag);
   SHIREConfig config;
   config.checkIPAddress = (has_tag ? ShibINI::boolean(tag) : false);
 
   string shib_cookie;
-  if (! ini.get_tag(serverName, "cookieName", true, &shib_cookie)) {
+  if (! ini.get_tag(application_id, "cookieName", true, &shib_cookie)) {
     ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
-                 "shire_check_user: no cookieName configuration for %s",
-                 serverName);
+                 "shire_check_user: no cookieName configuration for %s", application_id);
     return SERVER_ERROR;
   }
 
   string wayfLocation;
-  if (! ini.get_tag(serverName, "wayfURL", true, &wayfLocation)) {
+  if (! ini.get_tag(application_id, "wayfURL", true, &wayfLocation)) {
     ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
-                 "shire_check_user: no wayfURL configuration for %s",
-                 serverName);
+                 "shire_check_user: no wayfURL configuration for %s", application_id);
     return SERVER_ERROR;
   }
 
   string shireError;
-  if (! ini.get_tag(serverName, "shireError", true, &shireError)) {
+  if (! ini.get_tag(application_id, "shireError", true, &shireError)) {
     ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
-                 "shire_check_user: no shireError configuration for %s",
-                 serverName);
+                 "shire_check_user: no shireError configuration for %s", application_id);
     return SERVER_ERROR;
   }
 
-  has_tag = ini.get_tag(serverName, "supportContact", true, &tag);
+  has_tag = ini.get_tag(application_id, "supportContact", true, &tag);
   markupProcessor.insert("supportContact", has_tag ? tag : "");
-  has_tag = ini.get_tag(serverName, "logoLocation", true, &tag);
+  has_tag = ini.get_tag(application_id, "logoLocation", true, &tag);
   markupProcessor.insert("logoLocation", has_tag ? tag : "");
   markupProcessor.insert("requestURL", targeturl);
   
@@ -511,7 +490,7 @@ extern "C" int shire_post_handler (request_rec* r)
         rpc_handle = new RPCHandle(shib_target_sockname(), SHIBRPC_PROG, SHIBRPC_VERS_1);
         rpc_handle_key->setData(rpc_handle);
     }
-    SHIRE shire(rpc_handle, config, shire_url);
+    SHIRE shire(rpc_handle, config, unescaped_shire);
 
   // Process SHIRE POST
 
@@ -520,19 +499,17 @@ extern "C" int shire_post_handler (request_rec* r)
       
   try {
     string sslonly;
-    if (!ini.get_tag(serverName, "shireSSLOnly", true, &sslonly))
+    if (!ini.get_tag(application_id, "shireSSLOnly", true, &sslonly))
       ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
                    "shire_post_handler: no shireSSLOnly configuration");
     
     // Make sure this is SSL, if it should be
     if (ShibINI::boolean(sslonly) && strcmp(ap_http_method(r),"https"))
-      throw ShibTargetException (SHIBRPC_OK,
-                                "blocked non-SSL access to SHIRE POST processor");
+      throw ShibTargetException(SHIBRPC_OK, "blocked non-SSL access to SHIRE POST processor");
 
     // Make sure this is a POST
     if (strcasecmp (r->method, "POST"))
-      throw ShibTargetException (SHIBRPC_OK,
-                                "blocked non-POST to SHIRE POST processor");
+      throw ShibTargetException(SHIBRPC_OK, "blocked non-POST to SHIRE POST processor");
 
     // Sure sure this POST is an appropriate content type
     const char *ct = ap_table_get (r->headers_in, "Content-type");
@@ -575,24 +552,24 @@ extern "C" int shire_post_handler (request_rec* r)
 
     // process the post
     string cookie;
-    RPCError* status = shire.sessionCreate(post, r->connection->remote_ip, cookie);
+    RPCError* status = shire.sessionCreate(post, r->connection->remote_ip, application_id, cookie);
 
     if (status->isError()) {
       ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,
                    "shire_post_handler() POST process failed (%d): %s",
                    status->getCode(), status->getText());
 
-      if (status->isRetryable()) {
-       ap_log_rerror(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,r,
-                     "shire_post_handler() Retrying POST by redirecting to WAYF");
+    if (status->isRetryable()) {
+         ap_log_rerror(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,r,
+               "shire_post_handler() Retrying POST by redirecting to WAYF");
        
-       char* wayf=ap_pstrcat(r->pool,wayfLocation.c_str(),
-                             "?shire=",shire_location,
+        char* wayf=ap_pstrcat(r->pool,wayfLocation.c_str(),
+                             "?shire=",url_encode(r,unescaped_shire),
                              "&target=",url_encode(r,target),NULL);
-       ap_table_setn(r->headers_out,"Location",wayf);
-       delete status;
-       return REDIRECT;
-      }
+        ap_table_setn(r->headers_out,"Location",wayf);
+        delete status;
+        return REDIRECT;
+    }
 
       // return this error to the user.
       markupProcessor.insert (*status);
index 2fbf58d..77ad33a 100644 (file)
@@ -13,7 +13,7 @@
                        <element ref="appmap:Path" minOccurs="0" maxOccurs="unbounded"/>\r
                </sequence>\r
                <attribute name="Name" type="string" use="required"/>\r
-               <attribute name="ApplicationID" type="anyURI" use="optional"/>\r
+               <attribute name="ApplicationID" type="string" use="optional"/>\r
             <anyAttribute namespace="##any" processContents="lax"/>\r
         </complexType>\r
     </element>\r
@@ -36,7 +36,7 @@
                <attribute name="Scheme" type="appmap:SchemeType" use="optional" default="http"/>\r
                <attribute name="Name" type="string" use="required"/>\r
                <attribute name="Port" type="unsignedInt" use="optional"/>\r
-               <attribute name="ApplicationID" type="anyURI" use="optional"/>\r
+               <attribute name="ApplicationID" type="string" use="optional"/>\r
             <anyAttribute namespace="##any" processContents="lax"/>\r
        </complexType>\r
     </element>\r
@@ -46,7 +46,6 @@
             <sequence>\r
                 <element ref="appmap:Host" minOccurs="0" maxOccurs="unbounded"/>\r
             </sequence>\r
-               <attribute name="ApplicationID" type="anyURI" use="required"/>\r
             <anyAttribute namespace="##any" processContents="lax"/>\r
         </complexType>\r
     </element>\r
index f05dd56..13fd3af 100644 (file)
@@ -61,9 +61,9 @@ public:
   ShibMySQLCCacheEntry(const char *, CCacheEntry*, ShibMySQLCCache*);
   ~ShibMySQLCCacheEntry() {}
 
-  virtual Iterator<SAMLAssertion*> getAssertions(Resource& resource)
+  virtual Iterator<SAMLAssertion*> getAssertions(const char* resource)
        { return m_cacheEntry->getAssertions(resource); }
-  virtual void preFetch(Resource& resource, int prefetch_window)
+  virtual void preFetch(const char* resource, int prefetch_window)
        { m_cacheEntry->preFetch(resource, prefetch_window); }
   virtual bool isSessionValid(time_t lifetime, time_t timeout);
   virtual const char* getClientAddress()
index 3ed6968..8284b98 100644 (file)
@@ -22,7 +22,6 @@ libshib_target_la_SOURCES = \
        shib-config.cpp \
        shib-ini.cpp \
        shib-mlp.cpp \
-       shib-resource.cpp \
        shib-resourceentry.cpp \
        shib-rm.cpp \
        shib-rpcerror.cpp \
@@ -34,7 +33,9 @@ libshib_target_la_SOURCES = \
        shibrpc-clnt.c \
        shibrpc-server.cpp \
        shibrpc-svc.c \
-       shibrpc-xdr.c
+       shibrpc-xdr.c \
+       XML.cpp \
+       XMLApplicationMapper.cpp
 
 # this is different from the project version
 # http://sources.redhat.com/autobook/autobook/autobook_91.html
index 30f64ff..9426c82 100644 (file)
@@ -73,18 +73,21 @@ namespace shibtarget {
     
         struct Override
         {
-            Override(const XMLCh* AppID) : m_XMLChAppID(AppID), m_AppID(AppID) {}
+            Override(const XMLCh* AppID) : m_XMLChAppID((AppID && *AppID) ? AppID : NULL),
+                m_AppID((AppID && *AppID) ? AppID : NULL) {}
             ~Override();
             const Override* locate(const char* path) const;
             auto_ptr_char m_AppID;
             const XMLCh* m_XMLChAppID;
             map<string,Override*> m_map;
         };
+        
+        const Override* findOverride(const char* vhost, const char* path) const;
     
-        const XMLCh* m_XMLChAppID;
-        string m_AppID;
         map<string,Override*> m_map;
         map<string,Override*> m_extras;
+        
+        Category* log;
     
     private:
         Override* buildOverride(const XMLCh* appID, DOMElement* root, Category& log);
@@ -102,30 +105,10 @@ XMLApplicationMapperImpl::Override::~Override()
         delete i->second;
 }
 
-XMLApplicationMapperImpl::Override* XMLApplicationMapperImpl::buildOverride(const XMLCh* appID, DOMElement* root, Category& log)
-{
-    Override* o=new Override(appID);
-    DOMNodeList* nlist = root->getElementsByTagNameNS(shibtarget::XML::APPMAP_NS,shibtarget::XML::Literals::Path);
-    for (int i=0; nlist && i<nlist->getLength(); i++)
-    {
-        DOMElement* path=static_cast<DOMElement*>(nlist->item(i));
-        const XMLCh* name=path->getAttributeNS(NULL,shibboleth::XML::Literals::Name);
-        if (!name || !*name)
-        {
-            log.warn("Skipping Path element (%d) with empty Name attribute",i);
-            continue;
-        }
-        
-        auto_ptr_char n(name);
-        o->m_map[n.get()]=buildOverride(path->getAttributeNS(NULL,shibtarget::XML::Literals::ApplicationID),path,log);
-    }
-    return o;
-}
-
 XMLApplicationMapperImpl::XMLApplicationMapperImpl(const char* pathname) : ReloadableXMLFileImpl(pathname)
 {
     NDC ndc("XMLApplicationMapperImpl");
-    Category& log=Category::getInstance("shibtarget.XMLApplicationMapperImpl");
+    log=&Category::getInstance("shibtarget.XMLApplicationMapper");
 
     try
     {
@@ -133,47 +116,40 @@ XMLApplicationMapperImpl::XMLApplicationMapperImpl(const char* pathname) : Reloa
         if (XMLString::compareString(shibtarget::XML::APPMAP_NS,e->getNamespaceURI()) ||
             XMLString::compareString(shibtarget::XML::Literals::ApplicationMap,e->getLocalName()))
         {
-            log.error("Construction requires a valid app mapping file: (appmap:ApplicationMap as root element)");
+            log->error("Construction requires a valid app mapping file: (appmap:ApplicationMap as root element)");
             throw MetadataException("Construction requires a valid app mapping file: (appmap:ApplicationMap as root element)");
         }
         
-        m_XMLChAppID=e->getAttributeNS(NULL,shibtarget::XML::Literals::ApplicationID);
-        if (!m_XMLChAppID || !*m_XMLChAppID)
-        {
-            log.error("Default ApplicationID must be defined");
-            throw MetadataException("Default ApplicationID must be defined");
-        }
-        auto_ptr_char defappid(m_XMLChAppID);
-        m_AppID=defappid.get();
-
         // Loop over the Host elements.
         DOMNodeList* nlist = e->getElementsByTagNameNS(shibtarget::XML::APPMAP_NS,shibtarget::XML::Literals::Host);
         for (int i=0; nlist && i<nlist->getLength(); i++)
         {
             DOMElement* host=static_cast<DOMElement*>(nlist->item(i));
             const XMLCh* scheme=host->getAttributeNS(NULL,shibtarget::XML::Literals::Scheme);
-            const XMLCh* name=host->getAttributeNS(NULL,shibboleth::XML::Literals::Name);
             const XMLCh* port=host->getAttributeNS(NULL,shibtarget::XML::Literals::Port);
+            auto_ptr_XMLCh name(host->getAttributeNS(NULL,shibboleth::XML::Literals::Name));
 
-            if (!name || !*name)
+            if (!name.get() || !*(name.get()))
             {
-                log.warn("Skipping Host element (%d) with empty Name attribute",i);
+                log->warn("Skipping Host element (%d) with empty Name attribute",i);
                 continue;
             }
+            XMLString::lowerCase(const_cast<XMLCh*>(name.get()));
 
-            Override* o=buildOverride(host->getAttributeNS(NULL,shibtarget::XML::Literals::ApplicationID),host,log);
+            Override* o=buildOverride(host->getAttributeNS(NULL,shibtarget::XML::Literals::ApplicationID),host,*log);
 
             auto_ptr_char s(scheme);
-            auto_ptr_char n(name);
+            auto_ptr_char n(name.get());
             auto_ptr_char p(port);
-            string url(s.get() ? s.get() : "http");
+            string url((s.get() && *(s.get())) ? s.get() : "http");
             url=url + "://" + n.get();
-            if (p.get()==NULL)
+            if (p.get()==NULL || *(p.get())=='\0')
             {
                 // First store a port-less version.
                 if (m_map.count(url))
                 {
-                    log.warn("Skipping duplicate Host element (%s)",url.c_str());
+                    log->warn("Skipping duplicate Host element (%s)",url.c_str());
+                    delete o;
                     continue;
                 }
                 m_map[url]=o;
@@ -198,31 +174,35 @@ XMLApplicationMapperImpl::XMLApplicationMapperImpl(const char* pathname) : Reloa
                 url=url + ':' + p.get();
                 if (m_map.count(url))
                 {
-                    log.warn("Skipping duplicate Host element (%s)",url.c_str());
+                    log->warn("Skipping duplicate Host element (%s)",url.c_str());
+                    delete o;
                     continue;
                 }
                 m_map[url]=o;
             }
+            log->debug("Added <Host> mapping for %s",url.c_str());
         }
     }
     catch (SAMLException& e)
     {
-        log.errorStream() << "Error while parsing app mapping configuration: " << e.what() << CategoryStream::ENDLINE;
+        log->errorStream() << "Error while parsing app mapping configuration: " << e.what() << CategoryStream::ENDLINE;
         for (map<string,Override*>::iterator i=m_map.begin(); i!=m_map.end(); i++)
             delete i->second;
         if (m_doc)
             m_doc->release();
         throw;
     }
+#ifndef _DEBUG
     catch (...)
     {
-        log.error("Unexpected error while parsing app mapping configuration");
+        log->error("Unexpected error while parsing app mapping configuration");
         for (map<string,Override*>::iterator i=m_map.begin(); i!=m_map.end(); i++)
             delete i->second;
         if (m_doc)
             m_doc->release();
         throw;
     }
+#endif
 }
 
 XMLApplicationMapperImpl::~XMLApplicationMapperImpl()
@@ -231,17 +211,67 @@ XMLApplicationMapperImpl::~XMLApplicationMapperImpl()
         delete i->second;
 }
 
+XMLApplicationMapperImpl::Override* XMLApplicationMapperImpl::buildOverride(const XMLCh* appID, DOMElement* root, Category& log)
+{
+    Override* o=new Override(appID);
+    DOMNodeList* nlist = root->getElementsByTagNameNS(shibtarget::XML::APPMAP_NS,shibtarget::XML::Literals::Path);
+    for (int i=0; nlist && i<nlist->getLength(); i++)
+    {
+        DOMElement* path=static_cast<DOMElement*>(nlist->item(i));
+        auto_ptr_XMLCh name(path->getAttributeNS(NULL,shibboleth::XML::Literals::Name));
+        if (!name.get() || !*(name.get()))
+        {
+            log.warn("Skipping Path element (%d) with empty Name attribute",i);
+            continue;
+        }
+        XMLString::lowerCase(const_cast<XMLCh*>(name.get()));
+        
+        auto_ptr_char n(name.get());
+        o->m_map[n.get()]=buildOverride(path->getAttributeNS(NULL,shibtarget::XML::Literals::ApplicationID),path,log);
+    }
+    return o;
+}
+
+const XMLApplicationMapperImpl::Override* XMLApplicationMapperImpl::findOverride(const char* vhost, const char* path) const
+{
+    const Override* o=NULL;
+    map<string,Override*>::const_iterator i=m_map.find(vhost);
+    if (i!=m_map.end())
+        o=i->second;
+    else
+    {
+        i=m_extras.find(vhost);
+        if (i!=m_extras.end())
+            o=i->second;
+    }
+    
+    if (o)
+    {
+        const Override* o2=o->locate(path);
+        if (o2)
+            return o2;
+    }
+    return o;
+}
+
 const XMLApplicationMapperImpl::Override* XMLApplicationMapperImpl::Override::locate(const char* path) const
 {
     char* dup=strdup(path);
+    char* sep=strchr(path,'?');
+    if (sep)
+        *sep=0;
+    for (char* pch=dup; *pch; pch++)
+        *pch=tolower(*pch);
+        
+    
     const Override* o=this;
     const Override* specifier=((m_XMLChAppID && *m_XMLChAppID) ? this : NULL);
     
-#ifdef WIN32
-    const char* token=strtok(dup,"/");
-#else
+#ifdef HAVE_STRTOK_R
     char* pos=NULL;
     const char* token=strtok_r(dup,"/",&pos);
+#else
+    const char* token=strtok(dup,"/");
 #endif
     while (token)
     {
@@ -251,10 +281,10 @@ const XMLApplicationMapperImpl::Override* XMLApplicationMapperImpl::Override::lo
         o=i->second;
         if (o->m_XMLChAppID && *(o->m_XMLChAppID))
             specifier=o;
-#ifdef WIN32
-        token=strtok(NULL,"/");
-#else
+#ifdef HAVE_STRTOK_R
         token=strtok_r(NULL,"/",&pos);
+#else
+        token=strtok(NULL,"/");
 #endif
     }
 
@@ -285,38 +315,34 @@ const char* XMLApplicationMapper::getApplicationFromURL(const char* url) const
 {
     string vhost;
     const char* path=split_url(url,vhost);
+
     XMLApplicationMapperImpl* impl=dynamic_cast<XMLApplicationMapperImpl*>(getImplementation());
-    
-    map<string,XMLApplicationMapperImpl::Override*>::const_iterator i=impl->m_map.find(vhost);
-    if (i==impl->m_map.end())
-        i=impl->m_extras.find(vhost);
-    if (i!=impl->m_map.end())
+    const XMLApplicationMapperImpl::Override* o=impl->findOverride(vhost.c_str(), path);
+
+    if (impl->log->isDebugEnabled())
     {
-        const XMLApplicationMapperImpl::Override* o=i->second->locate(path);
-        if (o)
-            return o->m_AppID.get();
+        saml::NDC ndc("getApplicationFromURL");
+        impl->log->debug("mapped %s to %s", url, o ? o->m_AppID.get() : "default application ID");
     }
-    
-    return impl->m_AppID.c_str();
+
+    return o ? o->m_AppID.get() : "";
 }
 
 const XMLCh* XMLApplicationMapper::getXMLChApplicationFromURL(const char* url) const
 {
     string vhost;
     const char* path=split_url(url,vhost);
+
     XMLApplicationMapperImpl* impl=dynamic_cast<XMLApplicationMapperImpl*>(getImplementation());
-    
-    map<string,XMLApplicationMapperImpl::Override*>::const_iterator i=impl->m_map.find(vhost);
-    if (i==impl->m_map.end())
-        i=impl->m_extras.find(vhost);
-    if (i!=impl->m_map.end())
+    const XMLApplicationMapperImpl::Override* o=impl->findOverride(vhost.c_str(), path);
+
+    if (impl->log->isDebugEnabled())
     {
-        const XMLApplicationMapperImpl::Override* o=i->second->locate(path);
-        if (o)
-            return o->m_XMLChAppID;
+        saml::NDC ndc("getXMLChApplicationFromURL");
+        impl->log->debug("mapped %s to %s", url, o ? o->m_AppID.get() : "default application ID");
     }
-    
-    return impl->m_XMLChAppID;
+
+    return o ? o->m_XMLChAppID : &chNull;
 }
 
 const char* XMLApplicationMapper::getApplicationFromParsedURL(
@@ -334,17 +360,15 @@ const char* XMLApplicationMapper::getApplicationFromParsedURL(
     vhost+=buf;
 
     XMLApplicationMapperImpl* impl=dynamic_cast<XMLApplicationMapperImpl*>(getImplementation());
-    map<string,XMLApplicationMapperImpl::Override*>::const_iterator i=impl->m_map.find(vhost);
-    if (i==impl->m_map.end())
-        i=impl->m_extras.find(vhost);
-    if (i!=impl->m_map.end())
+    const XMLApplicationMapperImpl::Override* o=impl->findOverride(vhost.c_str(), path);
+
+    if (impl->log->isDebugEnabled())
     {
-        const XMLApplicationMapperImpl::Override* o=i->second->locate(path);
-        if (o)
-            return o->m_AppID.get();
+        saml::NDC ndc("getApplicationFromParsedURL");
+        impl->log->debug("mapped %s%s to %s", vhost.c_str(), path ? path : "", o ? o->m_AppID.get() : "default application ID");
     }
-    
-    return impl->m_AppID.c_str();
+
+    return o ? o->m_AppID.get() : "";
 }
 
 const XMLCh* XMLApplicationMapper::getXMLChApplicationFromParsedURL(
@@ -362,15 +386,13 @@ const XMLCh* XMLApplicationMapper::getXMLChApplicationFromParsedURL(
     vhost+=buf;
 
     XMLApplicationMapperImpl* impl=dynamic_cast<XMLApplicationMapperImpl*>(getImplementation());
-    map<string,XMLApplicationMapperImpl::Override*>::const_iterator i=impl->m_map.find(vhost);
-    if (i==impl->m_map.end())
-        i=impl->m_extras.find(vhost);
-    if (i!=impl->m_map.end())
+    const XMLApplicationMapperImpl::Override* o=impl->findOverride(vhost.c_str(), path);
+
+    if (impl->log->isDebugEnabled())
     {
-        const XMLApplicationMapperImpl::Override* o=i->second->locate(path);
-        if (o)
-            return o->m_XMLChAppID;
+        saml::NDC ndc("getXMLChApplicationFromParsedURL");
+        impl->log->debug("mapped %s%s to %s", vhost.c_str(), path ? path : "", o ? o->m_AppID.get() : "default application ID");
     }
-    
-    return impl->m_XMLChAppID;
+
+    return o ? o->m_XMLChAppID : &chNull;
 }
index a486c9f..a026044 100644 (file)
@@ -71,8 +71,8 @@ namespace shibtarget {
   class SHIBTARGET_EXPORTS CCacheEntry
   {
   public:
-    virtual saml::Iterator<saml::SAMLAssertion*> getAssertions(Resource& resource) = 0;
-    virtual void preFetch(Resource& resource, int prefetch_window) = 0;
+    virtual saml::Iterator<saml::SAMLAssertion*> getAssertions(const char* appId) = 0;
+    virtual void preFetch(const char* appId, int prefetch_window) = 0;
 
     virtual bool isSessionValid(time_t lifetime, time_t timeout) = 0;
     virtual const char* getClientAddress() = 0;
@@ -132,8 +132,7 @@ namespace shibtarget {
   class ResourceEntry
   {
   public:
-    ResourceEntry(const Resource&, const saml::SAMLSubject&, CCache *,
-                 const saml::Iterator<saml::SAMLAuthorityBinding*>);
+    ResourceEntry(const char*, const saml::SAMLSubject&, CCache*, const saml::Iterator<saml::SAMLAuthorityBinding*>);
     ~ResourceEntry();
 
     // Is this ResourceEntry going to be valid for the next <int> seconds?
index a801df1..80b8772 100644 (file)
@@ -84,6 +84,84 @@ using namespace saml;
 using namespace shibboleth;
 using namespace shibtarget;
 
+namespace shibtarget {
+
+    // An implementation of the URL->application mapping API using an XML file
+    class XMLApplicationMapper : public IApplicationMapper, public ReloadableXMLFile
+    {
+    public:
+        XMLApplicationMapper(const char* pathname) : ReloadableXMLFile(pathname) {}
+        ~XMLApplicationMapper() {}
+
+        const char* getApplicationFromURL(const char* url) const;
+        const XMLCh* getXMLChApplicationFromURL(const char* url) const;
+        const char* getApplicationFromParsedURL(
+            const char* scheme, const char* hostname, unsigned int port, const char* path=NULL
+            ) const;
+        const XMLCh* getXMLChApplicationFromParsedURL(
+            const char* scheme, const char* hostname, unsigned int port, const char* path=NULL
+            ) const;
+
+    protected:
+        virtual ReloadableXMLFileImpl* newImplementation(const char* pathname) const;
+    };
+
+    class STConfig : public ShibTargetConfig
+    {
+    public:
+        STConfig(const char* app_name, const char* inifile);
+        ~STConfig();
+        void ref();
+        void init();
+        void shutdown();
+        ShibINI& getINI() const { return *ini; }
+        IApplicationMapper* getApplicationMapper() const { return m_applicationMapper; }
+        saml::Iterator<IMetadata*> getMetadataProviders() const { return metadatas; }
+        saml::Iterator<ITrust*> getTrustProviders() const { return trusts; }
+        saml::Iterator<ICredentials*> getCredentialProviders() const { return creds; }
+        saml::Iterator<IAAP*> getAAPProviders() const { return aaps; }
+        saml::Iterator<const XMLCh*> getPolicies() const { return saml::Iterator<const XMLCh*>(policies); }
+     
+    private:
+        saml::SAMLConfig& samlConf;
+        shibboleth::ShibConfig& shibConf;
+        ShibINI* ini;
+        std::string m_app_name;
+        int refcount;
+        std::vector<const XMLCh*> policies;
+        std::string m_SocketName;
+#ifdef WANT_TCP_SHAR
+        std::vector<std::string> m_SocketACL;
+#endif
+        IApplicationMapper* m_applicationMapper;
+        std::vector<IMetadata*> metadatas;
+        std::vector<ITrust*> trusts;
+        std::vector<ICredentials*> creds;
+        std::vector<IAAP*> aaps;
+      
+        friend ShibSockName ::shib_target_sockname();
+        friend ShibSockName ::shib_target_sockacl(unsigned int);
+    };
+
+    class XML
+    {
+    public:
+        // URI constants
+        static const XMLCh APPMAP_NS[];
+        static const XMLCh APPMAP_SCHEMA_ID[];
+
+        struct Literals
+        {
+            static const XMLCh ApplicationID[];
+            static const XMLCh ApplicationMap[];
+            static const XMLCh Host[];
+            static const XMLCh Path[];
+            static const XMLCh Port[];
+            static const XMLCh Scheme[];
+        };
+    };
+}
+
 #endif
 
 #endif
index af3a0b3..1903782 100644 (file)
@@ -81,8 +81,8 @@ public:
   InternalCCacheEntry(SAMLAuthenticationStatement *s, const char *client_addr);
   ~InternalCCacheEntry();
 
-  virtual Iterator<SAMLAssertion*> getAssertions(Resource& resource);
-  virtual void preFetch(Resource& resource, int prefetch_window);
+  virtual Iterator<SAMLAssertion*> getAssertions(const char* resource);
+  virtual void preFetch(const char* resource, int prefetch_window);
   virtual bool isSessionValid(time_t lifetime, time_t timeout);
   virtual const char* getClientAddress() { return m_clientAddress.c_str(); }
   virtual const char* getSerializedStatement() { return m_statement.c_str(); }
@@ -94,10 +94,8 @@ public:
   void rdlock() { cacheitem_lock->rdlock(); }
   void wrlock() { cacheitem_lock->wrlock(); }
 
-  static vector<SAMLAssertion*> g_emptyVector;
-
 private:
-  ResourceEntry* populate(Resource& resource, int slop);
+  ResourceEntry* populate(const char* resource, int slop);
   ResourceEntry* find(const char* resource);
   void insert(const char* resource, ResourceEntry* entry);
   void remove(const char* resource);
@@ -131,13 +129,13 @@ private:
   class ResourceLock
   {
   public:
-    ResourceLock(InternalCCacheEntry* entry, string resource);
+    ResourceLock(InternalCCacheEntry* entry, const char* resource);
     ~ResourceLock();
 
   private:
-    Mutex*                     find(string& resource);
+    Mutex*                     find(const char* resource);
     InternalCCacheEntry*       entry;
-    string                     resource;
+    string                     m_resource;
   };
 
   friend class ResourceLock;
@@ -150,8 +148,7 @@ public:
   virtual ~InternalCCache();
 
   virtual CCacheEntry* find(const char* key);
-  virtual void insert(const char* key, SAMLAuthenticationStatement *s,
-                     const char *client_addr);
+  virtual void insert(const char* key, SAMLAuthenticationStatement *s, const char *client_addr);
   virtual void remove(const char* key);
 
   InternalCCacheEntry* findi(const char* key);
@@ -203,9 +200,6 @@ CCache* CCache::getInstance(const char* type)
   return (CCache*) new InternalCCache();
 }
 
-// static members
-vector<SAMLAssertion*> InternalCCacheEntry::g_emptyVector;
-
 
 /******************************************************************************/
 /* InternalCCache:  A Credential Cache                                        */
@@ -213,8 +207,7 @@ vector<SAMLAssertion*> InternalCCacheEntry::g_emptyVector;
 
 InternalCCache::InternalCCache()
 {
-  string ctx="shibtarget.InternalCCache";
-  log = &(log4cpp::Category::getInstance(ctx));
+  log = &(log4cpp::Category::getInstance("shibtarget.InternalCCache"));
   lock = RWLock::create();
 
   shutdown_wait = CondWait::create();
@@ -263,8 +256,7 @@ CCacheEntry* InternalCCache::find(const char* key)
   return dynamic_cast<CCacheEntry*>(entry);
 }
 
-void InternalCCache::insert(const char* key, SAMLAuthenticationStatement *s,
-                           const char *client_addr)
+void InternalCCache::insert(const char* key, SAMLAuthenticationStatement *s, const char *client_addr)
 {
   log->debug("caching new entry for \"%s\"", key);
 
@@ -409,8 +401,7 @@ void* InternalCCache::cleanup_fcn(void* cache_p)
 InternalCCacheEntry::InternalCCacheEntry(SAMLAuthenticationStatement *s, const char *client_addr)
   : m_hasbinding(false)
 {
-  string ctx = "shibtarget::InternalCCacheEntry";
-  log = &(log4cpp::Category::getInstance(ctx));
+  log = &(log4cpp::Category::getInstance("shibtarget::InternalCCacheEntry"));
   pop_locks_lock = Mutex::create();
   access_lock = Mutex::create();
   resource_lock = RWLock::create();
@@ -426,8 +417,8 @@ InternalCCacheEntry::InternalCCacheEntry(SAMLAuthenticationStatement *s, const c
   const XMLCh* name = m_subject->getName();
   const XMLCh* qual = m_subject->getNameQualifier();
 
-  auto_ptr<char> h(XMLString::transcode(name));
-  auto_ptr<char> d(XMLString::transcode(qual));
+  auto_ptr_char h(name);
+  auto_ptr_char d(qual);
 
   m_handle = h.get();
   m_originSite = d.get();
@@ -448,8 +439,7 @@ InternalCCacheEntry::InternalCCacheEntry(SAMLAuthenticationStatement *s, const c
   m_statement = os.str();
 
   log->info("New Session Created...");
-  log->debug("Handle: \"%s\", Site: \"%s\", Address: %s", h.get(), d.get(),
-            client_addr);
+  log->debug("Handle: \"%s\", Site: \"%s\", Address: %s", h.get(), d.get(), client_addr);
 }
 
 InternalCCacheEntry::~InternalCCacheEntry()
@@ -491,32 +481,31 @@ bool InternalCCacheEntry::isSessionValid(time_t lifetime, time_t timeout)
   return true;
 }
 
-Iterator<SAMLAssertion*> InternalCCacheEntry::getAssertions(Resource& resource)
+Iterator<SAMLAssertion*> InternalCCacheEntry::getAssertions(const char* resource)
 {
   saml::NDC ndc("getAssertions");
   ResourceEntry* entry = populate(resource, 0);
   if (entry)
     return entry->getAssertions();
-  return Iterator<SAMLAssertion*>(InternalCCacheEntry::g_emptyVector);
+  return EMPTY(SAMLAssertion*);
 }
 
-void InternalCCacheEntry::preFetch(Resource& resource, int prefetch_window)
+void InternalCCacheEntry::preFetch(const char* resource, int prefetch_window)
 {
   saml::NDC ndc("preFetch");
-  ResourceEntry* entry = populate(resource, prefetch_window);
+  populate(resource, prefetch_window);
 }
 
-ResourceEntry* InternalCCacheEntry::populate(Resource& resource, int slop)
+ResourceEntry* InternalCCacheEntry::populate(const char* resource, int slop)
 {
   saml::NDC ndc("populate");
-  log->debug("populating entry for %s (%s)",
-            resource.getResource(), resource.getURL());
+  log->debug("populating entry for %s", resource);
 
   // Lock the resource within this entry...
-  InternalCCacheEntry::ResourceLock lock(this, resource.getResource());
+  InternalCCacheEntry::ResourceLock lock(this, resource);
 
   // Can we use what we have?
-  ResourceEntry *entry = find(resource.getResource());
+  ResourceEntry *entry = find(resource);
   if (entry) {
     log->debug("found resource");
     if (entry->isValid(slop))
@@ -524,7 +513,7 @@ ResourceEntry* InternalCCacheEntry::populate(Resource& resource, int slop)
 
     // entry is invalid (expired) -- go fetch a new one.
     log->debug("removing resource cache; assertion is invalid");
-    remove (resource.getResource());
+    remove(resource);
     delete entry;
   }
 
@@ -536,25 +525,25 @@ ResourceEntry* InternalCCacheEntry::populate(Resource& resource, int slop)
   }
 
   log->info("trying to request attributes for %s@%s -> %s",
-           m_handle.c_str(), m_originSite.c_str(), resource.getURL());
+           m_handle.c_str(), m_originSite.c_str(), resource);
 
   try {
     entry = new ResourceEntry(resource, *m_subject, m_cache, p_auth->getBindings());
   } catch (ShibTargetException&) {
     return NULL;
   }
-  insert (resource.getResource(), entry);
+  insert(resource, entry);
 
   log->info("fetched and stored SAML response");
   return entry;
 }
 
-ResourceEntry* InternalCCacheEntry::find(const char* resource_url)
+ResourceEntry* InternalCCacheEntry::find(const char* resource)
 {
   ReadLock rwlock(resource_lock);
 
-  log->debug("find: %s", resource_url);
-  map<string,ResourceEntry*>::const_iterator i=m_resources.find(resource_url);
+  log->debug("find: %s", resource);
+  map<string,ResourceEntry*>::const_iterator i=m_resources.find(resource);
   if (i==m_resources.end()) {
     log->debug("no match found");
     return NULL;
@@ -589,9 +578,8 @@ void InternalCCacheEntry::remove(const char* resource)
 // will obtain and hold the proper lock until it goes out of scope and
 // deconstructs.
 
-InternalCCacheEntry::ResourceLock::ResourceLock(InternalCCacheEntry* entry,
-                                               string resource) :
-  entry(entry), resource(resource)
+InternalCCacheEntry::ResourceLock::ResourceLock(InternalCCacheEntry* entry, const char* resource) :
+  entry(entry), m_resource(resource)
 {
   Mutex *mutex = find(resource);
   mutex->lock();
@@ -599,11 +587,11 @@ InternalCCacheEntry::ResourceLock::ResourceLock(InternalCCacheEntry* entry,
 
 InternalCCacheEntry::ResourceLock::~ResourceLock()
 {
-  Mutex *mutex = find(resource);
+  Mutex *mutex = find(m_resource.c_str());
   mutex->unlock();
 }
 
-Mutex* InternalCCacheEntry::ResourceLock::find(string& resource)
+Mutex* InternalCCacheEntry::ResourceLock::find(const char* resource)
 {
   Lock(entry->pop_locks_lock);
   
index 9bb9686..8172dcf 100644 (file)
 #define SHIBTARGET_INIFILE "/opt/shibboleth/etc/shibboleth/shibboleth.ini"
 #endif
 
-class STConfig : public ShibTargetConfig
-{
-public:
-  STConfig(const char* app_name, const char* inifile);
-  ~STConfig();
-  void shutdown();
-  void init();
-  ShibINI& getINI() { return *ini; }
-
-  Iterator<const XMLCh*> getPolicies() { return Iterator<const XMLCh*>(policies); }
-
-  void ref();
-private:
-  SAMLConfig& samlConf;
-  ShibConfig& shibConf;
-  ShibINI* ini;
-  string m_app_name;
-  int refcount;
-  vector<const XMLCh*> policies;
-  string m_SocketName;
-#ifdef WANT_TCP_SHAR
-  vector<string> m_SocketACL;
-#endif
-  friend ShibSockName shib_target_sockname();
-  friend ShibSockName shib_target_sockacl(unsigned int);
-};
-
 namespace {
   STConfig * g_Config = NULL;
   Mutex * g_lock = NULL;
@@ -100,6 +73,7 @@ namespace {
 
 CCache* shibtarget::g_shibTargetCCache = NULL;
 
+
 /****************************************************************************/
 // External Interface
 
@@ -141,7 +115,7 @@ ShibTargetConfig& ShibTargetConfig::getConfig()
 
 STConfig::STConfig(const char* app_name, const char* inifile)
   :  samlConf(SAMLConfig::getConfig()), shibConf(ShibConfig::getConfig()),
-     m_app_name(app_name), refcount(0)
+     m_app_name(app_name), m_applicationMapper(NULL), refcount(0)
 {
   try {
     ini = new ShibINI((inifile ? inifile : SHIBTARGET_INIFILE));
@@ -240,54 +214,67 @@ void STConfig::init()
     delete iter;
   }
 
-  // Load the specified metadata.
-  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())
-    {
-        string sources=ini->get(tag,*prov);
-        int j = 0;
-        for (int i = 0; i < sources.length(); i++)
-        {
-            if (sources.at(i) == ';')
-            {
-                string val = sources.substr(j, i-j);
-                j = i+1;
-                log.info("registering metadata provider: type=%s, source=%s",prov->c_str(),val.c_str());
-                if (!shibConf.addMetadata(prov->c_str(),val.c_str()))
-                {
-                    log.crit("error adding metadata provider: type=%s, source=%s",prov->c_str(),val.c_str());
-                    if (app == SHIBTARGET_SHAR)
-                        throw runtime_error("error adding metadata provider");
-                }
-            }
+    // Load the specified metadata, trust, creds, and aap sources.
+    const string* prov;
+    ShibINI::Iterator* iter=ini->tag_iterator(SHIBTARGET_TAG_METADATA);
+    for (prov=iter->begin(); prov; prov=iter->next()) {
+        string source=ini->get(SHIBTARGET_TAG_METADATA,*prov);
+        log.info("building metadata provider: type=%s, source=%s",prov->c_str(),source.c_str());
+        try {
+            metadatas.push_back(shibConf.newMetadata(prov->c_str(),source.c_str()));
         }
-        string val = sources.substr(j, sources.length()-j);
-        log.info("registering metadata provider: type=%s, source=%s",prov->c_str(),val.c_str());
-        if (!shibConf.addMetadata(prov->c_str(),val.c_str()))
-        {
-            log.crit("error adding metadata provider: type=%s, source=%s",prov->c_str(),val.c_str());
+        catch (exception& e) {
+            log.crit("error building metadata provider: type=%s, source=%s (%s)",prov->c_str(),source.c_str(),e.what());
             if (app == SHIBTARGET_SHAR)
-                throw runtime_error("error adding metadata provider");
+                throw;
         }
     }
     delete iter;
-  }
-  
-  // Backward-compatibility-hack to pull in aap-uri from [shire] and load
-  // as attribute metadata. We load this for anything, not just the SHIRE.
-  if (ini->get_tag(SHIBTARGET_SHIRE, "aap-uri", false, &tag))
-  {
-    log.warn("using DEPRECATED aap-uri setting for backward compatibility, please read the latest target deploy guide");
-    log.info("registering metadata provider: type=edu.internet2.middleware.shibboleth.target.AAP.XML, source=%s",tag.c_str());
-    if (!shibConf.addMetadata("edu.internet2.middleware.shibboleth.target.AAP.XML",tag.c_str()))
-    {
-        log.crit("error adding metadata provider: type=edu.internet2.middleware.shibboleth.target.AAP.XML, source=%s",tag.c_str());
-        if (!strcmp(app.c_str(), SHIBTARGET_SHAR))
-            throw runtime_error("error adding metadata provider");
+
+    iter=ini->tag_iterator(SHIBTARGET_TAG_AAP);
+    for (prov=iter->begin(); prov; prov=iter->next()) {
+        string source=ini->get(SHIBTARGET_TAG_AAP,*prov);
+        log.info("building AAP provider: type=%s, source=%s",prov->c_str(),source.c_str());
+        try {
+            aaps.push_back(shibConf.newAAP(prov->c_str(),source.c_str()));
+        }
+        catch (exception& e) {
+            log.crit("error building AAP provider: type=%s, source=%s (%s)",prov->c_str(),source.c_str(),e.what());
+            if (app == SHIBTARGET_SHAR)
+                throw;
+        }
+    }
+    delete iter;
+    
+    if (app == SHIBTARGET_SHAR) {
+        iter=ini->tag_iterator(SHIBTARGET_TAG_TRUST);
+        for (prov=iter->begin(); prov; prov=iter->next()) {
+            string source=ini->get(SHIBTARGET_TAG_TRUST,*prov);
+            log.info("building trust provider: type=%s, source=%s",prov->c_str(),source.c_str());
+            try {
+                trusts.push_back(shibConf.newTrust(prov->c_str(),source.c_str()));
+            }
+            catch (exception& e) {
+                log.crit("error building trust provider: type=%s, source=%s (%s)",prov->c_str(),source.c_str(),e.what());
+                throw;
+            }
+        }
+        delete iter;
+    
+        iter=ini->tag_iterator(SHIBTARGET_TAG_CREDS);
+        for (prov=iter->begin(); prov; prov=iter->next()) {
+            string source=ini->get(SHIBTARGET_TAG_CREDS,*prov);
+            log.info("building creds provider: type=%s, source=%s",prov->c_str(),source.c_str());
+            try {
+                creds.push_back(shibConf.newCredentials(prov->c_str(),source.c_str()));
+            }
+            catch (exception& e) {
+                log.crit("error building creds provider: type=%s, source=%s (%s)",prov->c_str(),source.c_str(),e.what());
+                throw;
+            }
+        }
+        delete iter;
     }
-  }
   
   // Load SAML policies.
   if (ini->exists(SHIBTARGET_POLICIES)) {
@@ -300,8 +287,22 @@ void STConfig::init()
     delete iter;
   }
   
+  if (app == SHIBTARGET_SHIRE && ini->get_tag(app, SHIBTARGET_TAG_APPMAPPER, false, &tag)) {
+    saml::XML::registerSchema(shibtarget::XML::APPMAP_NS,shibtarget::XML::APPMAP_SCHEMA_ID);
+    try {
+        m_applicationMapper=new XMLApplicationMapper(tag.c_str());
+        dynamic_cast<XMLApplicationMapper*>(m_applicationMapper)->getImplementation();
+    }
+    catch (exception& e) {
+        log.crit("caught exception while loading URL->Application mapping file (%s)", e.what());
+    }
+    catch (...) {
+        log.crit("caught unknown exception while loading URL->Application mapping file");
+    }
+  }
+  
   // Initialize the SHAR Cache
-  if (!strcmp (app.c_str(), SHIBTARGET_SHAR)) {
+  if (app == SHIBTARGET_SHAR) {
     const char * cache_type = NULL;
     if (ini->get_tag (app, SHIBTARGET_TAG_CACHETYPE, true, &tag))
       cache_type = tag.c_str();
@@ -341,9 +342,23 @@ void STConfig::init()
 
 STConfig::~STConfig()
 {
+  delete m_applicationMapper;
+
   for (vector<const XMLCh*>::iterator i=policies.begin(); i!=policies.end(); i++)
     delete const_cast<XMLCh*>(*i);
-  
+
+  for (vector<IMetadata*>::iterator j=metadatas.begin(); j!=metadatas.end(); j++)
+    delete (*j);
+
+  for (vector<ITrust*>::iterator k=trusts.begin(); k!=trusts.end(); k++)
+    delete (*k);
+    
+  for (vector<ICredentials*>::iterator l=creds.begin(); l!=creds.end(); l++)
+    delete (*l);
+
+  for (vector<IAAP*>::iterator m=aaps.begin(); m!=aaps.end(); m++)
+    delete (*m);
+
   delete g_shibTargetCCache;
   delete ini;
 
@@ -378,3 +393,10 @@ extern "C" ShibSockName shib_target_sockacl(unsigned int index)
 #endif
     return (ShibSockName)0;
 }
+
+ApplicationMapper::ApplicationMapper() : m_mapper(ShibTargetConfig::getConfig().getApplicationMapper())
+{
+    if (!m_mapper)
+        throw runtime_error("application mapper not initialized, check log for errors");
+    m_mapper->lock();
+}
diff --git a/shib-target/shib-resource.cpp b/shib-target/shib-resource.cpp
deleted file mode 100644 (file)
index 91ffe78..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * The Shibboleth License, Version 1.
- * Copyright (c) 2002
- * University Corporation for Advanced Internet Development, Inc.
- * All rights reserved
- *
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution, if any, must include
- * the following acknowledgment: "This product includes software developed by
- * the University Corporation for Advanced Internet Development
- * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement
- * may appear in the software itself, if and wherever such third-party
- * acknowledgments normally appear.
- *
- * Neither the name of Shibboleth nor the names of its contributors, nor
- * Internet2, nor the University Corporation for Advanced Internet Development,
- * Inc., nor UCAID may be used to endorse or promote products derived from this
- * software without specific prior written permission. For written permission,
- * please contact shibboleth@shibboleth.org
- *
- * Products derived from this software may not be called Shibboleth, Internet2,
- * UCAID, or the University Corporation for Advanced Internet Development, nor
- * may Shibboleth appear in their name, without prior written permission of the
- * University Corporation for Advanced Internet Development.
- *
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
- * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK
- * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY
- * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * shib-resource.cpp -- an interface to Shibboleth Resources (URL applications)
- *
- * Created by: Derek Atkins <derek@ihtfp.com>
- *
- * $Id$
- */
-
-#include "internal.h"
-
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
-#include <stdexcept>
-
-class shibtarget::ResourcePriv
-{
-public:
-  ResourcePriv(const char *str);
-  ~ResourcePriv();
-
-  string m_url;
-  string m_resource;
-  log4cpp::Category* log;
-  vector<SAMLAttribute*> designators;
-};
-
-ResourcePriv::ResourcePriv(const char *str)
-{
-  string ctx = "shibtarget.Resource";
-  log = &(log4cpp::Category::getInstance(ctx));
-
-  m_url = str;
-
-  // XXX: The Resource is just the hostname!
-  const char* colon=strchr(str,':');
-  const char* slash=strchr(colon+3,'/');
-  m_resource = m_url.substr(0, slash-str);
-
-  log->info("creating resource: \"%s\" -> \"%s\"", str, m_resource.c_str());
-
-  // Now figure out the designators
-  string server = m_url.substr(colon-str+3, slash-(colon+3));
-
-  log->debug("server is \"%s\"", server.c_str());
-
-  ShibTargetConfig& config = ShibTargetConfig::getConfig();
-  ShibINI& ini = config.getINI();
-
-  string tag;
-  if (ini.get_tag (server, SHIBTARGET_TAG_REQATTRS, true, &tag)) {
-    // Now parse the request attributes tag...
-
-    log->debug("Request Attributes: \"%s\"", tag.c_str());
-
-    auto_ptr<char> tag_str(strdup(tag.c_str()));
-
-    char *tags = tag_str.get(), *tagptr = NULL, *the_tag;
-#ifdef HAVE_STRTOK_R
-    while ((the_tag = strtok_r(tags, " \t\r\n", &tagptr)) != NULL && *the_tag) {
-#else
-    while ((the_tag = strtok(tags, " \t\r\n")) != NULL && *the_tag) {
-#endif
-      // Make sure we don't loop ad-infinitum
-      tags = NULL;
-
-      log->debug ("Parsed attribute string: \"%s\"", the_tag);
-      log->debug ("tagptr = %p", tagptr);
-      
-      // transcode the attribute string from the tag
-      auto_ptr<XMLCh> temp(XMLString::transcode(the_tag));
-
-      // Now create the SAML Attribute from this name
-      try {
-       SAMLAttribute *attr =
-         new SAMLAttribute(temp.get(),
-                           shibboleth::Constants::SHIB_ATTRIBUTE_NAMESPACE_URI);
-       if (attr)
-         designators.push_back(attr);
-      } catch ( ... ) { }
-    }
-  } else
-    log->debug ("No request-attributes found");
-}
-
-ResourcePriv::~ResourcePriv()
-{
-  for (vector<SAMLAttribute*>::iterator i = designators.begin();
-       i != designators.end(); i++)
-    delete *i;
-}
-
-// Internal Class Definition
-
-Resource::Resource(const char *resource_url)
-{
-  // XXX: Perform some computation based on the URL...
-  m_priv = new ResourcePriv(resource_url);
-}
-
-Resource::Resource(string resource_url)
-{
-  m_priv = new ResourcePriv(resource_url.c_str());
-}
-
-Resource::~Resource()
-{
-  delete m_priv;
-}
-
-const char* Resource::getResource() const
-{
-  return m_priv->m_resource.c_str();
-}
-
-const char* Resource::getURL() const
-{
-  return m_priv->m_url.c_str();
-}
-
-bool Resource::equals(Resource* r2) const
-{
-  return (!strcmp (m_priv->m_url.c_str(), r2->m_priv->m_url.c_str()));
-}
-
-Iterator<SAMLAttribute*> Resource::getDesignators() const
-{
-  return Iterator<SAMLAttribute*>(m_priv->designators);
-}
index 4fc9ff0..5218fbe 100644 (file)
@@ -84,8 +84,7 @@ public:
 
 ResourceEntryPriv::ResourceEntryPriv() : m_response(NULL), defaultLife(-1)
 {
-  string ctx = "shibtarget::ResourceEntry";
-  log = &(log4cpp::Category::getInstance(ctx));
+  log = &(log4cpp::Category::getInstance("shibtarget::ResourceEntry"));
   createTime = time(NULL);
 
   // Compute and cache the default life for this Resource Entry
@@ -105,36 +104,68 @@ ResourceEntryPriv::~ResourceEntryPriv()
     delete m_response;
 }
 
-ResourceEntry::ResourceEntry(const Resource &resource,
+ResourceEntry::ResourceEntry(const char* resource,
                             const SAMLSubject& p_subject,
                             CCache *m_cache,
                             const Iterator<SAMLAuthorityBinding*> AAbindings)
 {
   saml::NDC ndc("ResourceEntry()");
 
+  string tag;
+  ShibTargetConfig& conf=ShibTargetConfig::getConfig();
+  ShibINI& ini = conf.getINI();
+  if (!ini.get_tag(resource, "providerID", true, &tag))
+    throw ShibTargetException(SHIBRPC_INTERNAL_ERROR,string("unable to determine ProviderID for request, not set?"));
+  auto_ptr_XMLCh providerID(tag.c_str());
+
+  vector<SAMLAttributeDesignator*> designators;
   auto_ptr<ResourceEntryPriv> priv(new ResourceEntryPriv());
 
-  auto_ptr<XMLCh> resourceURL(XMLString::transcode(resource.getURL()));
+  // Look up attributes to request based on resource ID
+  if (ini.get_tag (resource, SHIBTARGET_TAG_REQATTRS, true, &tag)) {
+    // Now parse the request attributes tag...
+    priv->log->debug("Request Attributes: \"%s\"", tag.c_str());
+
+    auto_ptr<char> tag_str(strdup(tag.c_str()));
+    char *tags = tag_str.get(), *tagptr = NULL, *the_tag;
+#ifdef HAVE_STRTOK_R
+    while ((the_tag = strtok_r(tags, " \t\r\n", &tagptr)) != NULL && *the_tag) {
+#else
+    while ((the_tag = strtok(tags, " \t\r\n")) != NULL && *the_tag) {
+#endif
+      // Make sure we don't loop ad-infinitum
+      tags = NULL;
+
+      priv->log->debug ("Parsed attribute string: \"%s\"", the_tag);
+      priv->log->debug ("tagptr = %p", tagptr);
+      
+      // transcode the attribute string from the tag
+      auto_ptr_XMLCh temp(the_tag);
 
-  // Clone the subject...
-  // 1) I know the static_cast is safe from clone()
-  // 2) the AttributeQuery will destroy this new subject.
-  auto_ptr<SAMLSubject> subject(static_cast<SAMLSubject*>(p_subject.clone()));
+      // Now create the SAML Attribute from this name
+      designators.push_back(new SAMLAttributeDesignator(temp.get(),shibboleth::Constants::SHIB_ATTRIBUTE_NAMESPACE_URI));
+    }
+  }
+  else
+    priv->log->debug ("No request-attributes found, requesting any/all");
 
   // Build a SAML Request....
-  SAMLAttributeQuery* q=new SAMLAttributeQuery(subject.get(),resourceURL.get(),
-                                              resource.getDesignators().clone());
-  subject.release();
+  SAMLAttributeQuery* q=new SAMLAttributeQuery(
+    static_cast<SAMLSubject*>(p_subject.clone()),providerID.get(),designators
+    );
   auto_ptr<SAMLRequest> req(new SAMLRequest(EMPTY(QName),q));
 
   // Try this request against all the bindings in the AuthenticationStatement
   // (i.e. send it to each AA in the list of bindings)
   SAMLResponse* response = NULL;
-  OriginMetadata site(p_subject.getNameQualifier());
+  OriginMetadata site(conf.getMetadataProviders(),p_subject.getNameQualifier());
   if (site.fail())
       throw MetadataException("unable to locate origin site's metadata during attribute query");
-  auto_ptr<XMLCh> caller(XMLString::transcode(resource.getResource()));
-  auto_ptr<SAMLBinding> pBinding(SAMLBindingFactory::getInstance(caller.get(),site));
+  auto_ptr<SAMLBinding> pBinding(
+    SAMLBindingFactory::getInstance(
+        conf.getMetadataProviders(),conf.getTrustProviders(),conf.getCredentialProviders(),providerID.get(),site
+        )
+    );
 
   while (!response && AAbindings.hasNext()) {
     SAMLAuthorityBinding* binding = AAbindings.next();
@@ -147,7 +178,20 @@ ResourceEntry::ResourceEntry(const Resource &resource,
   // Make sure we got a response
   if (!response) {
     priv->log->info ("No Response");
-    throw new ShibTargetException();
+    throw ShibTargetException();
+  }
+
+  // Run it through the AAP. Note that we could end up with an empty response!
+  Iterator<SAMLAssertion*> a=response->getAssertions();
+  for (unsigned long i=0; i < a.size();) {
+      try {
+          AAP::apply(conf.getAAPProviders(),site,*(a[i]));
+          i++;
+      }
+      catch (SAMLException&) {
+          priv->log->info("no statements remain, removing assertion");
+          response->removeAssertion(i);
+      }
   }
 
   priv->m_response = response;
@@ -182,7 +226,7 @@ bool ResourceEntry::isValid(int slop)
 #endif
   char timebuf[32];
   strftime(timebuf,32,"%Y-%m-%dT%H:%M:%SZ",ptime);
-  auto_ptr<XMLCh> timeptr(XMLString::transcode(timebuf));
+  auto_ptr_XMLCh timeptr(timebuf);
   XMLDateTime curDateTime(timeptr.get());
   curDateTime.parseDateTime();
 
@@ -197,12 +241,12 @@ bool ResourceEntry::isValid(int slop)
     const XMLDateTime* thistime = assertion->getNotOnOrAfter();
 
     // If there is no time, then just continue and ignore this assertion.
-    if (! thistime)
+    if (!thistime)
       continue;
 
     count++;
-    auto_ptr<char> nowptr(XMLString::transcode(curDateTime.toString()));
-    auto_ptr<char> assnptr(XMLString::transcode(thistime->toString()));
+    auto_ptr_char nowptr(curDateTime.getRawData());
+    auto_ptr_char assnptr(thistime->getRawData());
 
     m_priv->log->debug ("comparing now (%s) to %s", nowptr.get(), assnptr.get());
     int result=XMLDateTime::compareOrder(&curDateTime, thistime);
index 5584e02..9932ff3 100644 (file)
@@ -99,8 +99,7 @@ RM::~RM()
   delete m_priv;
 }
 
-RPCError* RM::getAssertions(const char* cookie, const char* ip,
-                           const char* url,
+RPCError* RM::getAssertions(const char* cookie, const char* ip, const char* resource,
                            vector<SAMLAssertion*> &assertions,
                            SAMLAuthenticationStatement **statement)
 {
@@ -117,19 +116,14 @@ RPCError* RM::getAssertions(const char* cookie, const char* ip,
     return new RPCError(-1, "No IP Address");
   }
 
-  if (!url || *url == '\0') {
-    m_priv->log->error ("no URL");
-    return new RPCError(-1, "Invalid URL Resource");
-  }
-
-  m_priv->log->info ("request from %s for \"%s\"", ip, url);
+  m_priv->log->info ("request from %s for \"%s\"", ip, resource);
   m_priv->log->debug ("session cookie: %s", cookie);
 
   shibrpc_get_assertions_args_1 arg;
   arg.cookie.cookie = (char*)cookie;
   arg.cookie.client_addr = (char*)ip;
   arg.checkIPAddress = m_priv->m_config.checkIPAddress;
-  arg.url = (char *)url;
+  arg.application_id = (char *)resource;
 
   shibrpc_get_assertions_ret_1 ret;
   memset (&ret, 0, sizeof(ret));
@@ -185,7 +179,7 @@ RPCError* RM::getAssertions(const char* cookie, const char* ip,
            while (conds.hasNext())
            {
              SAMLAudienceRestrictionCondition* cond=dynamic_cast<SAMLAudienceRestrictionCondition*>(conds.next());
-             if (!cond->eval(ShibTargetConfig::getConfig().getPolicies()))
+          if (!cond->eval(dynamic_cast<STConfig&>(ShibTargetConfig::getConfig()).getPolicies()))
              {
                m_priv->log->warn("Assertion failed AudienceRestrictionCondition check, skipping it...");
                ok=false;
@@ -242,22 +236,7 @@ void RM::serialize(SAMLAssertion &assertion, string &result)
   os << assertion;
   unsigned int outlen;
   char* assn = (char*) os.str().c_str();
-  XMLByte* serialized = Base64::encode(reinterpret_cast<XMLByte*>(assn),
-                                      os.str().length(), &outlen);
+  XMLByte* serialized = Base64::encode(reinterpret_cast<XMLByte*>(assn), os.str().length(), &outlen);
   result = (char*) serialized;
-}
-
-Iterator<SAMLAttribute*> RM::getAttributes(SAMLAssertion &assertion)
-{
-  // XXX: Only deal with a single statement!!!!
-  Iterator<SAMLStatement*> i = assertion.getStatements();
-  if (i.hasNext()) {
-    SAMLAttributeStatement* s =
-       static_cast<SAMLAttributeStatement*>(const_cast<SAMLStatement*>(i.next()));
-
-    if (s)
-      return s->getAttributes();
-  }
-  
-  return EMPTY(SAMLAttribute*);
+  XMLString::release(&serialized);
 }
index 123c516..3c44b01 100644 (file)
@@ -312,7 +312,7 @@ string RPCError::getOriginErrorURL()
     string res="No URL Available";
     if (m_priv->origin)
     {
-        OriginMetadata mapper(m_priv->origin);
+        OriginMetadata mapper(ShibTargetConfig::getConfig().getMetadataProviders(),m_priv->origin);
         if (!mapper.fail())
         {
             const char* temp=mapper->getErrorURL();
@@ -328,7 +328,7 @@ string RPCError::getOriginContactName()
     string res="No Name Available";
     if (m_priv->origin)
     {
-        OriginMetadata mapper(m_priv->origin);
+        OriginMetadata mapper(ShibTargetConfig::getConfig().getMetadataProviders(),m_priv->origin);
         Iterator<const IContactInfo*> i=
             mapper.fail() ? EMPTY(const IContactInfo*) : mapper->getContacts();
         while (i.hasNext())
@@ -349,7 +349,7 @@ string RPCError::getOriginContactEmail()
     string res="No Email Available";
     if (m_priv->origin)
     {
-        OriginMetadata mapper(m_priv->origin);
+        OriginMetadata mapper(ShibTargetConfig::getConfig().getMetadataProviders(),m_priv->origin);
         Iterator<const IContactInfo*> i=
             mapper.fail() ? EMPTY(const IContactInfo*) : mapper->getContacts();
         while (i.hasNext())
index 7131843..1c79832 100644 (file)
 class shibtarget::SHIREPriv
 {
 public:
-  SHIREPriv(RPCHandle *rpc, SHIREConfig cfg, string shire_url);
+  SHIREPriv(RPCHandle *rpc, SHIREConfig cfg, const char* shire_url);
   ~SHIREPriv();
 
   RPCHandle *  m_rpc;
   SHIREConfig  m_config;
-  string       m_url;
+  string           m_shire_url;
 
   log4cpp::Category* log;
 };
 
-SHIREPriv::SHIREPriv(RPCHandle *rpc, SHIREConfig cfg, string shire_url)
+SHIREPriv::SHIREPriv(RPCHandle *rpc, SHIREConfig cfg, const char* shire_url)
 {
   string ctx = "shibtarget.SHIRE";
   log = &(log4cpp::Category::getInstance(ctx));
   m_rpc = rpc;
   m_config = cfg;
-  m_url = shire_url;
+  m_shire_url = shire_url;
 }
 
 SHIREPriv::~SHIREPriv() {}
 
 
-SHIRE::SHIRE(RPCHandle *rpc, SHIREConfig cfg, string shire_url)
+SHIRE::SHIRE(RPCHandle *rpc, SHIREConfig cfg, const char* shire_url)
 {
   m_priv = new SHIREPriv(rpc, cfg, shire_url);
   m_priv->log->info ("New SHIRE handle created: %p", m_priv);
@@ -100,7 +100,7 @@ SHIRE::~SHIRE()
 }
 
 
-RPCError* SHIRE::sessionIsValid(const char* cookie, const char* ip, const char* url)
+RPCError* SHIRE::sessionIsValid(const char* cookie, const char* ip, const char* application_id)
 {
   saml::NDC ndc("sessionIsValid");
 
@@ -115,7 +115,7 @@ RPCError* SHIRE::sessionIsValid(const char* cookie, const char* ip, const char*
   }
 
   // make sure we pass _something_ to the server
-  if (!url) url = "";
+  if (!application_id) application_id = "";
 
   m_priv->log->info ("is session valid: %s", ip);
   m_priv->log->debug ("session cookie: %s", cookie);
@@ -124,7 +124,7 @@ RPCError* SHIRE::sessionIsValid(const char* cookie, const char* ip, const char*
 
   arg.cookie.cookie = (char*)cookie;
   arg.cookie.client_addr = (char *)ip;
-  arg.url = (char *)url;
+  arg.application_id = (char *)application_id;
   arg.lifetime = m_priv->m_config.lifetime;
   arg.timeout = m_priv->m_config.timeout;
   arg.checkIPAddress = m_priv->m_config.checkIPAddress;
@@ -170,7 +170,7 @@ RPCError* SHIRE::sessionIsValid(const char* cookie, const char* ip, const char*
   return retval;
 }
 
-RPCError* SHIRE::sessionCreate(const char* post, const char* ip, string& cookie)
+RPCError* SHIRE::sessionCreate(const char* post, const char* ip, const char* application_id, string& cookie)
 {
   saml::NDC ndc("sessionCreate");
 
@@ -184,10 +184,14 @@ RPCError* SHIRE::sessionCreate(const char* post, const char* ip, string& cookie)
     return new RPCError(-1, "Invalid IP Address");
   }
 
+  // make sure we pass _something_ to the server
+  if (!application_id) application_id = "";
+
   m_priv->log->info ("create session for user at %s", ip);
 
   shibrpc_new_session_args_1 arg;
-  arg.shire_location = (char*) (m_priv->m_url.c_str());
+  arg.shire_location = (char*) (m_priv->m_shire_url.c_str());
+  arg.application_id = (char*) application_id;
   arg.saml_post = (char*)post;
   arg.client_addr = (char*)ip;
   arg.checkIPAddress = m_priv->m_config.checkIPAddress;
index 86a3147..9aee470 100644 (file)
@@ -160,6 +160,10 @@ SHIBTARGET_EXPORTS void shib_sock_close (ShibSocket s, ShibSockName name);
 #define SHIBTARGET_TAG_SAMLCOMPAT   "SAMLCompat"
 
 #define SHIBTARGET_TAG_METADATA "metadata"
+#define SHIBTARGET_TAG_TRUST    "trust"
+#define SHIBTARGET_TAG_CREDS    "credentials"
+#define SHIBTARGET_TAG_AAP      "aap"
+#define SHIBTARGET_TAG_APPMAPPER "applicationMap"
 
 #define SHIBTARGET_TAG_DEFAULTLIFE  "defaultLife"
 
@@ -182,23 +186,6 @@ SHIBTARGET_EXPORTS ShibSockName shib_target_sockacl(unsigned int index);
 
 
 namespace shibtarget {
-  class ResourcePriv;
-  class SHIBTARGET_EXPORTS Resource
-  {
-  public:
-    Resource(const char* resource_url);
-    Resource(std::string resource_url);
-    ~Resource();
-
-    const char* getResource() const;
-    const char* getURL() const;
-    bool equals(Resource*) const;
-    saml::Iterator<saml::SAMLAttribute*> getDesignators() const;
-
-  private:
-    ResourcePriv *m_priv;
-  };
-
   class RPCHandleInternal;
   class SHIBTARGET_EXPORTS RPCHandle
   {
@@ -360,16 +347,11 @@ namespace shibtarget {
   class SHIBTARGET_EXPORTS SHIRE
   {
   public:
-    SHIRE(RPCHandle *rpc, SHIREConfig config, std::string shire_url);
+    SHIRE(RPCHandle *rpc, SHIREConfig config, const char* shire_url);
     ~SHIRE();
 
-    RPCError* sessionIsValid(const char* cookie, const char* ip, const char* url);
-    RPCError* sessionCreate(const char* post, const char* ip,
-                            std::string &cookie);
-
-    //ShibTargetResponse* is_valid(ShibINI& ini, const char* serverName,
-    //                  const char *cookie, const char *target_url);
-    //ShibTargetResponse* create();
+    RPCError* sessionIsValid(const char* cookie, const char* ip, const char* application_id);
+    RPCError* sessionCreate(const char* post, const char* ip, const char* application_id, std::string &cookie);
 
   private:
     SHIREPriv *m_priv;
@@ -388,12 +370,10 @@ namespace shibtarget {
     RM(RPCHandle *rpc, RMConfig config);
     ~RM();
 
-    RPCError* getAssertions(const char* cookie, const char* ip,
-                           const char* url,
+    RPCError* getAssertions(const char* cookie, const char* ip, const char* application_id,
                            std::vector<saml::SAMLAssertion*> &assertions,
                            saml::SAMLAuthenticationStatement **statement = NULL);
     static void serialize(saml::SAMLAssertion &assertion, std::string &result);
-    static saml::Iterator<saml::SAMLAttribute*> getAttributes(saml::SAMLAssertion &assertion);
   private:
     RMPriv *m_priv;
   };
@@ -493,6 +473,35 @@ namespace shibtarget {
     void init(std::string& file, bool case_sensitive);
   };
 
+    // Abstract API to map URLs to application names
+    struct SHIBTARGET_EXPORTS IApplicationMapper : public virtual shibboleth::ILockable
+    {
+        virtual const char* getApplicationFromURL(const char* url) const=0;
+        virtual const XMLCh* getXMLChApplicationFromURL(const char* url) const=0;
+        virtual const char* getApplicationFromParsedURL(
+            const char* scheme, const char* hostname, unsigned int port, const char* path=NULL
+            ) const=0;
+        virtual const XMLCh* getXMLChApplicationFromParsedURL(
+            const char* scheme, const char* hostname, unsigned int port, const char* path=NULL
+            ) const=0;
+        virtual ~IApplicationMapper() {}
+    };
+
+    // A helper class to wrap the lock/unlock sequence.
+    class SHIBTARGET_EXPORTS ApplicationMapper
+    {
+    public:
+        ApplicationMapper();
+        ~ApplicationMapper() {if (m_mapper) m_mapper->unlock();}
+        const IApplicationMapper* operator->() const {return m_mapper;}
+        operator const IApplicationMapper*() const {return m_mapper;}
+        
+    private:
+        ApplicationMapper(const ApplicationMapper&);
+        void operator=(const ApplicationMapper&);
+        IApplicationMapper* m_mapper;
+    };
+    
   class SHIBTARGET_EXPORTS ShibTargetConfig
   {
   public:
@@ -501,9 +510,13 @@ namespace shibtarget {
     static ShibTargetConfig& getConfig();
     virtual void init() = 0;
     virtual void shutdown() = 0;
+    virtual shibtarget::ShibINI& getINI() const = 0;
+    virtual IApplicationMapper* getApplicationMapper() const = 0;
+    virtual saml::Iterator<shibboleth::IMetadata*> getMetadataProviders() const = 0;
+    virtual saml::Iterator<shibboleth::ITrust*> getTrustProviders() const = 0;
+    virtual saml::Iterator<shibboleth::ICredentials*> getCredentialProviders() const = 0;
+    virtual saml::Iterator<shibboleth::IAAP*> getAAPProviders() const = 0;
     virtual ~ShibTargetConfig() {}
-    virtual ShibINI& getINI() = 0;
-    virtual saml::Iterator<const XMLCh*> getPolicies() = 0;
   };
 
 } // namespace
index 4be0296..c99cd57 100644 (file)
@@ -169,9 +169,8 @@ shibrpc_session_is_valid_1_svc(shibrpc_session_is_valid_args_1 *argp,
     // and now try to prefetch the attributes .. this could cause an
     // "error", which is why we call it here.
     try {
-      log.debug ("resource: %s", argp->url);
-      Resource r(argp->url);
-      entry->preFetch(r,15);   // give a 15-second window for the RM
+      log.debug ("resource: %s", argp->application_id);
+      entry->preFetch(argp->application_id, 15);       // give a 15-second window for the RM
 
     } catch (SAMLException &e) {
       log.debug ("prefetch failed with a SAML Exception: %s", e.what());
@@ -226,15 +225,16 @@ shibrpc_new_session_1_svc(shibrpc_new_session_args_1 *argp,
   auto_ptr_XMLCh location(argp->shire_location);
 
   // Pull in the Policies
-  Iterator<const XMLCh*> policies=ShibTargetConfig::getConfig().getPolicies();
+  Iterator<const XMLCh*> policies=dynamic_cast<STConfig&>(ShibTargetConfig::getConfig()).getPolicies();
 
   // And grab the Profile
   // XXX: Create a "Global" POSTProfile instance per location...
   log.debug ("create the POST profile (%d policies)", policies.size());
-  ShibPOSTProfile *profile =
-    ShibPOSTProfileFactory::getInstance(policies,
-                                       location.get(),
-                                       3600);
+  ShibPOSTProfile *profile = ShibPOSTProfileFactory::getInstance(
+    ShibTargetConfig::getConfig().getMetadataProviders(),
+    ShibTargetConfig::getConfig().getTrustProviders(),
+    policies,location.get(),3600
+    );
 
   SAMLResponse* r = NULL;
   const SAMLAuthenticationStatement* auth_st = NULL;
@@ -375,7 +375,7 @@ shibrpc_get_assertions_1_svc(shibrpc_get_assertions_args_1 *argp,
 
   log.debug ("get attrs for client at %s", argp->cookie.client_addr);
   log.debug ("cookie: %s", argp->cookie.cookie);
-  log.debug ("resource: %s", argp->url);
+  log.debug ("resource: %s", argp->application_id);
 
   // Find this session
   CCacheEntry* entry = g_shibTargetCCache->find(argp->cookie.cookie);
@@ -404,8 +404,7 @@ shibrpc_get_assertions_1_svc(shibrpc_get_assertions_args_1 *argp,
 
   try {
     // grab the attributes for this resource
-    Resource resource(argp->url);
-    Iterator<SAMLAssertion*> iter = entry->getAssertions(resource);
+    Iterator<SAMLAssertion*> iter = entry->getAssertions(argp->application_id);
     u_int size = iter.size();
     result->assertions.assertions_len = size;
 
@@ -413,17 +412,16 @@ shibrpc_get_assertions_1_svc(shibrpc_get_assertions_args_1 *argp,
     if (size) {
 
       // Build the response section
-      ShibRpcXML* av =
-       (ShibRpcXML*) malloc (size * sizeof (ShibRpcXML));
+      ShibRpcXML* av = (ShibRpcXML*) malloc (size * sizeof (ShibRpcXML));
       result->assertions.assertions_val = av;
 
       // and then serialize them all...
       u_int i = 0;
       while (iter.hasNext()) {
-       SAMLAssertion* as = iter.next();
-       ostringstream os;
-       os << *as;
-       av[i++].xml_string = strdup(os.str().c_str());
+        SAMLAssertion* as = iter.next();
+        ostringstream os;
+        os << *as;
+        av[i++].xml_string = strdup(os.str().c_str());
       }
     }
   } catch (SAMLException& e) {
index f9af9cb..74c22b4 100644 (file)
@@ -70,15 +70,15 @@ shibrpc_prog_1(struct svc_req *rqstp, register SVCXPRT *transp)
                return;
        }
        memset ((char *)&argument, 0, sizeof (argument));
-       if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
+       if (!svc_getargs (transp, _xdr_argument, (caddr_t) &argument)) {
                svcerr_decode (transp);
                return;
        }
        retval = (bool_t) (*local)((char *)&argument, (void *)&result, rqstp);
-       if (retval > 0 && !svc_sendreply(transp, (xdrproc_t) _xdr_result, (char *)&result)) {
+       if (retval > 0 && !svc_sendreply(transp, _xdr_result, (char *)&result)) {
                svcerr_systemerr (transp);
        }
-       if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
+       if (!svc_freeargs (transp, _xdr_argument, (caddr_t) &argument)) {
                fprintf (stderr, "%s", "unable to free arguments");
                exit (1);
        }
index d0dd1eb..c786c18 100644 (file)
@@ -80,7 +80,7 @@ xdr_shibrpc_session_is_valid_args_1 (XDR *xdrs, shibrpc_session_is_valid_args_1
 
         if (!xdr_ShibRpcHttpCookie_1 (xdrs, &objp->cookie))
                 return FALSE;
-        if (!xdr_string (xdrs, &objp->url, ~0))
+        if (!xdr_string (xdrs, &objp->application_id, ~0))
                 return FALSE;
         if (!xdr_bool (xdrs, &objp->checkIPAddress))
                 return FALSE;
@@ -106,6 +106,8 @@ xdr_shibrpc_new_session_args_1 (XDR *xdrs, shibrpc_new_session_args_1 *objp)
 {
        register int32_t *buf;
 
+        if (!xdr_string (xdrs, &objp->application_id, ~0))
+                return FALSE;
         if (!xdr_string (xdrs, &objp->shire_location, ~0))
                 return FALSE;
         if (!xdr_string (xdrs, &objp->saml_post, ~0))
@@ -138,7 +140,7 @@ xdr_shibrpc_get_assertions_args_1 (XDR *xdrs, shibrpc_get_assertions_args_1 *obj
                 return FALSE;
         if (!xdr_bool (xdrs, &objp->checkIPAddress))
                 return FALSE;
-        if (!xdr_string (xdrs, &objp->url, ~0))
+        if (!xdr_string (xdrs, &objp->application_id, ~0))
                 return FALSE;
        return TRUE;
 }
index 3b1f47c..c60f1b1 100644 (file)
@@ -8,9 +8,7 @@
 
 #include <rpc/rpc.h>
 
-#ifndef WIN32
 #include <pthread.h>
-#endif
 
 #ifdef __cplusplus
 extern "C" {
@@ -60,7 +58,7 @@ typedef struct ShibRpcXML ShibRpcXML;
 
 struct shibrpc_session_is_valid_args_1 {
        ShibRpcHttpCookie_1 cookie;
-       char *url;
+       char *application_id;
        bool_t checkIPAddress;
        long lifetime;
        long timeout;
@@ -73,6 +71,7 @@ struct shibrpc_session_is_valid_ret_1 {
 typedef struct shibrpc_session_is_valid_ret_1 shibrpc_session_is_valid_ret_1;
 
 struct shibrpc_new_session_args_1 {
+       char *application_id;
        char *shire_location;
        char *saml_post;
        char *client_addr;
@@ -89,7 +88,7 @@ typedef struct shibrpc_new_session_ret_1 shibrpc_new_session_ret_1;
 struct shibrpc_get_assertions_args_1 {
        ShibRpcHttpCookie_1 cookie;
        bool_t checkIPAddress;
-       char *url;
+       char *application_id;
 };
 typedef struct shibrpc_get_assertions_args_1 shibrpc_get_assertions_args_1;
 
index 3348b76..decff43 100644 (file)
@@ -65,7 +65,7 @@ struct ShibRpcXML {
 
 struct shibrpc_session_is_valid_args_1 {
   ShibRpcHttpCookie_1  cookie;
-  string               url<>;
+  string               application_id<>;
   bool                 checkIPAddress;
   long                 lifetime;
   long                 timeout;
@@ -76,6 +76,7 @@ struct shibrpc_session_is_valid_ret_1 {
 };
 
 struct shibrpc_new_session_args_1 {
+  string       application_id<>;
   string       shire_location<>;
   string       saml_post<>;
   string       client_addr<>;
@@ -91,7 +92,7 @@ struct shibrpc_new_session_ret_1 {
 struct shibrpc_get_assertions_args_1 {
   ShibRpcHttpCookie_1  cookie;
   bool                 checkIPAddress;
-  string               url<>;
+  string               application_id<>;
 };
 
 struct shibrpc_get_assertions_ret_1 {
index f36c435..f34611f 100644 (file)
@@ -115,10 +115,6 @@ SOURCE=".\shib-mlp.cpp"
 # End Source File
 # Begin Source File
 
-SOURCE=".\shib-resource.cpp"
-# End Source File
-# Begin Source File
-
 SOURCE=".\shib-resourceentry.cpp"
 # End Source File
 # Begin Source File
@@ -173,5 +169,13 @@ SOURCE=".\shibrpc-xdr.c"
 
 SOURCE=.\shibrpc.h
 # End Source File
+# Begin Source File
+
+SOURCE=.\XML.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\XMLApplicationMapper.cpp
+# End Source File
 # End Target
 # End Project
index b7ba035..f91ae77 100644 (file)
@@ -70,14 +70,12 @@ using namespace std;
 
 namespace shibboleth {
 
-    class XMLAAPImpl
+    class XMLAAPImpl : public ReloadableXMLFileImpl
     {
     public:
         XMLAAPImpl(const char* pathname);
         ~XMLAAPImpl();
         
-        void regAttributes() const;
-    
         class AttributeRule : public IAttributeRule
         {
         public:
@@ -89,18 +87,19 @@ namespace shibboleth {
             const char* getFactory() const { return m_factory.get(); }
             const char* getAlias() const { return m_alias.get(); }
             const char* getHeader() const { return m_header.get(); }
-            bool accept(const XMLCh* originSite, const DOMElement* e) const;
+            void apply(const IOriginSite* originSite, SAMLAttribute& attribute) const;
     
             enum value_type { literal, regexp, xpath };
         private:    
             const XMLCh* m_name;
             const XMLCh* m_namespace;
-            auto_ptr<char> m_factory;
-            auto_ptr<char> m_alias;
-            auto_ptr<char> m_header;
+            auto_ptr_char m_factory;
+            auto_ptr_char m_alias;
+            auto_ptr_char m_header;
             
             value_type toValueType(const DOMElement* e);
-            bool scopeCheck(const XMLCh* originSite, const DOMElement* e) const;
+            bool scopeCheck(const IOriginSite* originSite, const DOMElement* e) const;
+            bool accept(const IOriginSite* originSite, const DOMElement* e) const;
             
             struct SiteRule
             {
@@ -128,50 +127,51 @@ namespace shibboleth {
         typedef map<string,AttributeRule*> attrmap_t;
     #endif
         attrmap_t m_attrMap;
-        DOMDocument* m_doc;
     };
 
-    class XMLAAP : public IAAP
+    class XMLAAP : public IAAP, public ReloadableXMLFile
     {
     public:
-        XMLAAP(const char* pathname);
-        ~XMLAAP() { delete m_lock; delete m_impl; }
+        XMLAAP(const char* pathname) : ReloadableXMLFile(pathname) {}
+        ~XMLAAP() {}
         
-        void lock();
-        void unlock() { m_lock->unlock(); }
         const IAttributeRule* lookup(const XMLCh* attrName, const XMLCh* attrNamespace=NULL) const;
         const IAttributeRule* lookup(const char* alias) const;
-        saml::Iterator<const IAttributeRule*> getAttributeRules() const;
+        Iterator<const IAttributeRule*> getAttributeRules() const;
 
-    private:
-        std::string m_source;
-        time_t m_filestamp;
-        RWLock* m_lock;
-        XMLAAPImpl* m_impl;
+    protected:
+        virtual ReloadableXMLFileImpl* newImplementation(const char* pathname) const;
     };
 
 }
 
 extern "C" IAAP* XMLAAPFactory(const char* source)
 {
-    return new XMLAAP(source);
+    XMLAAP* aap=new XMLAAP(source);
+    try
+    {
+        aap->getImplementation();
+    }
+    catch (...)
+    {
+        delete aap;
+        throw;
+    }
+    return aap;    
+}
+
+ReloadableXMLFileImpl* XMLAAP::newImplementation(const char* pathname) const
+{
+    return new XMLAAPImpl(pathname);
 }
 
-XMLAAPImpl::XMLAAPImpl(const char* pathname) : m_doc(NULL)
+XMLAAPImpl::XMLAAPImpl(const char* pathname) : ReloadableXMLFileImpl(pathname)
 {
     NDC ndc("XMLAAPImpl");
     Category& log=Category::getInstance(SHIB_LOGCAT".XMLAAPImpl");
 
-    saml::XML::Parser p;
     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);
-        m_doc=p.parse(dsrc);
-
-        log.infoStream() << "Loaded and parsed AAP file (" << pathname << ")" << CategoryStream::ENDLINE;
-
         DOMElement* e = m_doc->getDocumentElement();
         if (XMLString::compareString(XML::SHIB_NS,e->getNamespaceURI()) ||
             XMLString::compareString(SHIB_L(AttributeAcceptancePolicy),e->getLocalName()))
@@ -189,12 +189,12 @@ XMLAAPImpl::XMLAAPImpl(const char* pathname) : m_doc(NULL)
             xstring key=rule->getName();
             key=key + chBang + chBang + (rule->getNamespace() ? rule->getNamespace() : Constants::SHIB_ATTRIBUTE_NAMESPACE_URI);
 #else
-            auto_ptr<char> aname(XMLString::transcode(rule->getName()));
+            auto_ptr_char aname(rule->getName());
             string key(aname.get());
             key+="!!";
             if (rule->getNamespace())
             {
-                auto_ptr<char> ans(XMLString::transcode(rule->getNamespace()));
+                auto_ptr_char ans(rule->getNamespace());
                 key+=ans.get();
             }
             else
@@ -208,7 +208,7 @@ XMLAAPImpl::XMLAAPImpl(const char* pathname) : m_doc(NULL)
     }
     catch (SAMLException& e)
     {
-        log.errorStream() << "XML error while parsing AAP: " << e.what() << CategoryStream::ENDLINE;
+        log.errorStream() << "Error while parsing AAP: " << e.what() << CategoryStream::ENDLINE;
         for (attrmap_t::iterator i=m_attrMap.begin(); i!=m_attrMap.end(); i++)
             delete i->second;
         if (m_doc)
@@ -230,28 +230,13 @@ XMLAAPImpl::XMLAAPImpl(const char* pathname) : m_doc(NULL)
 XMLAAPImpl::~XMLAAPImpl()
 {
     for (attrmap_t::iterator i=m_attrMap.begin(); i!=m_attrMap.end(); i++)
-    {
-        SAMLAttribute::unregFactory(i->second->getName(),i->second->getNamespace());
         delete i->second;
-    }
-    if (m_doc)
-        m_doc->release();
-}
-
-void XMLAAPImpl::regAttributes() const
-{
-    for (attrmap_t::const_iterator i=m_attrMap.begin(); i!=m_attrMap.end(); i++)
-    {
-        SAMLAttributeFactory* f=ShibConfig::getConfig().getAttributeFactory(i->second->getFactory());
-        if (f)
-            SAMLAttribute::regFactory(i->second->getName(),i->second->getNamespace(),f);
-    }
 }
 
 XMLAAPImpl::AttributeRule::AttributeRule(const DOMElement* e) :
-    m_factory(e->hasAttributeNS(NULL,SHIB_L(Factory)) ? XMLString::transcode(e->getAttributeNS(NULL,SHIB_L(Factory))) : NULL),
-    m_alias(e->hasAttributeNS(NULL,SHIB_L(Alias)) ? XMLString::transcode(e->getAttributeNS(NULL,SHIB_L(Alias))) : NULL),
-    m_header(e->hasAttributeNS(NULL,SHIB_L(Header)) ? XMLString::transcode(e->getAttributeNS(NULL,SHIB_L(Header))) : NULL)
+    m_factory(e->hasAttributeNS(NULL,SHIB_L(Factory)) ? e->getAttributeNS(NULL,SHIB_L(Factory)) : NULL),
+    m_alias(e->hasAttributeNS(NULL,SHIB_L(Alias)) ? e->getAttributeNS(NULL,SHIB_L(Alias)) : NULL),
+    m_header(e->hasAttributeNS(NULL,SHIB_L(Header)) ? e->getAttributeNS(NULL,SHIB_L(Header)) : NULL)
     
 {
     static const XMLCh wTrue[] = {chLatin_t, chLatin_r, chLatin_u, chLatin_e, chNull};
@@ -317,7 +302,7 @@ XMLAAPImpl::AttributeRule::AttributeRule(const DOMElement* e) :
         m_siteMap[srulename]=SiteRule();
         SiteRule& srule=m_siteMap[srulename];
 #else
-        auto_ptr<char> srulename2(XMLString::transcode(srulename));
+        auto_ptr_char srulename2(srulename);
         m_siteMap[srulename2.get()]=SiteRule();
         SiteRule& srule=m_siteMap[srulename2.get()];
 #endif
@@ -370,106 +355,38 @@ XMLAAPImpl::AttributeRule::value_type XMLAAPImpl::AttributeRule::toValueType(con
     throw MalformedException("Found an invalid value or scope rule type.");
 }
 
-XMLAAP::XMLAAP(const char* pathname) : m_filestamp(0), m_source(pathname), 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 XMLAAPImpl(pathname);
-    SAMLConfig::getConfig().saml_lock();
-    m_impl->regAttributes();
-    SAMLConfig::getConfig().saml_unlock();
-    m_lock=RWLock::create();
-}
-
-void XMLAAP::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
-                {
-                    XMLAAPImpl* new_mapper=new XMLAAPImpl(m_source.c_str());
-                    SAMLConfig::getConfig().saml_lock();
-                    delete m_impl;
-                    m_impl=new_mapper;
-                    m_impl->regAttributes();
-                    SAMLConfig::getConfig().saml_unlock();
-                    m_filestamp=stat_buf.st_mtime;
-                    m_lock->unlock();
-                }
-                catch(SAMLException& e)
-                {
-                    m_lock->unlock();
-                    saml::NDC ndc("lock");
-                    Category::getInstance(SHIB_LOGCAT".XMLAAP").error("failed to reload AAP, sticking with what we have: %s", e.what());
-                }
-                catch(...)
-                {
-                    m_lock->unlock();
-                    saml::NDC ndc("lock");
-                    Category::getInstance(SHIB_LOGCAT".XMLAAP").error("caught an unknown exception, sticking with what we have");
-                }
-            }
-            else
-            {
-                m_lock->unlock();
-            }
-            m_lock->rdlock();
-        }
-    }
-}
-
 const IAttributeRule* XMLAAP::lookup(const XMLCh* attrName, const XMLCh* attrNamespace) const
 {
 #ifdef HAVE_GOOD_STL
     xstring key=attrName;
     key=key + chBang + chBang + (attrNamespace ? attrNamespace : Constants::SHIB_ATTRIBUTE_NAMESPACE_URI);
 #else
-    auto_ptr<char> aname(XMLString::transcode(attrName));
+    auto_ptr_char aname(attrName);
     string key=aname.get();
     key+="!!";
     if (attrNamespace)
     {
-        auto_ptr<char> ans(XMLString::transcode(attrNamespace));
+        auto_ptr_char ans(attrNamespace);
         key+=ans.get();
     }
     else
         key+="urn:mace:shibboleth:1.0:attributeNamespace:uri";
 #endif
-    XMLAAPImpl::attrmap_t::const_iterator i=m_impl->m_attrMap.find(key);
-    return (i==m_impl->m_attrMap.end()) ? NULL : i->second;
+    XMLAAPImpl* impl=dynamic_cast<XMLAAPImpl*>(getImplementation());
+    XMLAAPImpl::attrmap_t::const_iterator i=impl->m_attrMap.find(key);
+    return (i==impl->m_attrMap.end()) ? NULL : i->second;
 }
 
 const IAttributeRule* XMLAAP::lookup(const char* alias) const
 {
-    map<string,const IAttributeRule*>::const_iterator i=m_impl->m_aliasMap.find(alias);
-    return (i==m_impl->m_aliasMap.end()) ? NULL : i->second;
+    XMLAAPImpl* impl=dynamic_cast<XMLAAPImpl*>(getImplementation());
+    map<string,const IAttributeRule*>::const_iterator i=impl->m_aliasMap.find(alias);
+    return (i==impl->m_aliasMap.end()) ? NULL : i->second;
 }
 
 Iterator<const IAttributeRule*> XMLAAP::getAttributeRules() const
 {
-    return m_impl->m_attrs;
+    return dynamic_cast<XMLAAPImpl*>(getImplementation())->m_attrs;
 }
 
 namespace {
@@ -491,7 +408,7 @@ namespace {
     }
 }
 
-bool XMLAAPImpl::AttributeRule::scopeCheck(const XMLCh* originSite, const DOMElement* e) const
+bool XMLAAPImpl::AttributeRule::scopeCheck(const IOriginSite* originSite, const DOMElement* e) const
 {
     // Are we scoped?
     const XMLCh* scope=e->getAttributeNS(NULL,SHIB_L(Scope));
@@ -513,8 +430,8 @@ bool XMLAAPImpl::AttributeRule::scopeCheck(const XMLCh* originSite, const DOMEle
         {
             if (log.isWarnEnabled())
             {
-                auto_ptr<char> temp(XMLString::transcode(m_name));
-                auto_ptr<char> temp2(XMLString::transcode(scope));
+                auto_ptr_char temp(m_name);
+                auto_ptr_char temp2(scope);
                 log.warn("attribute %s scope {%s} denied by any-site AAP, rejecting it",temp.get(),temp2.get());
             }
             return false;
@@ -524,9 +441,9 @@ bool XMLAAPImpl::AttributeRule::scopeCheck(const XMLCh* originSite, const DOMEle
     }
 
 #ifdef HAVE_GOOD_STL
-    const XMLCh* os=originSite;
+    const XMLCh* os=originSite->getName();
 #else
-    auto_ptr<char> pos(XMLString::transcode(originSite));
+    auto_ptr_char pos(originSite->getName());
     const char* os=pos.get();
 #endif
     sitemap_t::const_iterator srule=m_siteMap.find(os);
@@ -540,8 +457,8 @@ bool XMLAAPImpl::AttributeRule::scopeCheck(const XMLCh* originSite, const DOMEle
             {
                 if (log.isWarnEnabled())
                 {
-                    auto_ptr<char> temp(XMLString::transcode(m_name));
-                    auto_ptr<char> temp2(XMLString::transcode(scope));
+                    auto_ptr_char temp(m_name);
+                    auto_ptr_char temp2(scope);
                     log.warn("attribute %s scope {%s} denied by site AAP, rejecting it",temp.get(),temp2.get());
                 }
                 return false;
@@ -581,9 +498,7 @@ bool XMLAAPImpl::AttributeRule::scopeCheck(const XMLCh* originSite, const DOMEle
     }
     
     // If we still can't decide, defer to site metadata.
-    OriginMetadata mapper(originSite);
-    Iterator<pair<const XMLCh*,bool> > domains=
-        (mapper.fail()) ? Iterator<pair<const XMLCh*,bool> >() : mapper->getSecurityDomains();
+    Iterator<pair<const XMLCh*,bool> > domains=originSite->getSecurityDomains();
     while (domains.hasNext())
     {
         const pair<const XMLCh*,bool>& p=domains.next();
@@ -596,22 +511,22 @@ bool XMLAAPImpl::AttributeRule::scopeCheck(const XMLCh* originSite, const DOMEle
 
     if (log.isWarnEnabled())
     {
-        auto_ptr<char> temp(XMLString::transcode(m_name));
-        auto_ptr<char> temp2(XMLString::transcode(scope));
+        auto_ptr_char temp(m_name);
+        auto_ptr_char temp2(scope);
         log.warn("attribute %s scope {%s} not accepted",temp.get(),temp2.get());
     }
     return false;
 }
 
-bool XMLAAPImpl::AttributeRule::accept(const XMLCh* originSite, const DOMElement* e) const
+bool XMLAAPImpl::AttributeRule::accept(const IOriginSite* originSite, const DOMElement* e) const
 {
     NDC ndc("accept");
     Category& log=Category::getInstance(SHIB_LOGCAT".XMLAAPImpl");
     
     if (log.isDebugEnabled())
     {
-        auto_ptr<char> temp(XMLString::transcode(m_name));
-        auto_ptr<char> temp2(XMLString::transcode(originSite));
+        auto_ptr_char temp(m_name);
+        auto_ptr_char temp2(originSite->getName());
         log.debug("evaluating value for attribute %s from site %s",temp.get(),temp2.get());
     }
     
@@ -639,9 +554,9 @@ bool XMLAAPImpl::AttributeRule::accept(const XMLCh* originSite, const DOMElement
     }
 
 #ifdef HAVE_GOOD_STL
-    const XMLCh* os=originSite;
+    const XMLCh* os=originSite->getName();
 #else
-    auto_ptr<char> pos(XMLString::transcode(originSite));
+    auto_ptr_char pos(originSite->getName());
     const char* os=pos.get();
 #endif
     sitemap_t::const_iterator srule=m_siteMap.find(os);
@@ -649,8 +564,8 @@ bool XMLAAPImpl::AttributeRule::accept(const XMLCh* originSite, const DOMElement
     {
         if (log.isWarnEnabled())
         {
-            auto_ptr<char> temp(XMLString::transcode(m_name));
-            auto_ptr<char> temp2(XMLString::transcode(originSite));
+            auto_ptr_char temp(m_name);
+            auto_ptr_char temp2(originSite->getName());
             log.warn("site %s not found in attribute %s ruleset, any value is rejected",temp2.get(),temp.get());
         }
         return false;
@@ -676,10 +591,25 @@ bool XMLAAPImpl::AttributeRule::accept(const XMLCh* originSite, const DOMElement
 
     if (log.isWarnEnabled())
     {
-        auto_ptr<char> temp(XMLString::transcode(m_name));
-        auto_ptr<char> temp2(XMLString::transcode(n->getNodeValue()));
+        auto_ptr_char temp(m_name);
+        auto_ptr_char temp2(n->getNodeValue());
         log.warn("%sattribute %s value {%s} could not be validated by AAP, rejecting it",
                  (bSimple ? "" : "complex "),temp.get(),temp2.get());
     }
     return false;
 }
+
+void XMLAAPImpl::AttributeRule::apply(const IOriginSite* originSite, SAMLAttribute& attribute) const
+{
+    // Check each value.
+    Iterator<const DOMElement*> vals=attribute.getValueElements();
+    for (unsigned int i=0; i < vals.size();) {
+        if (!accept(originSite,vals[i]))
+            attribute.removeValue(i);
+        else
+            i++;
+    }
+    
+    // Now see if we trashed it irrevocably.
+    attribute.checkValidity();
+}
index 6d3dcfa..d31036f 100644 (file)
@@ -61,11 +61,15 @@ using namespace shibboleth;
 using namespace saml;
 using namespace std;
 
-ClubShibPOSTProfile::ClubShibPOSTProfile(const Iterator<const XMLCh*>& policies, const XMLCh* receiver, int ttlSeconds)
-    : ShibPOSTProfile(policies,receiver,ttlSeconds) {}
+ClubShibPOSTProfile::ClubShibPOSTProfile(
+    const Iterator<IMetadata*>& metadatas, const Iterator<ITrust*>& trusts,
+    const Iterator<const XMLCh*>& policies, const XMLCh* receiver, int ttlSeconds
+    ) : ShibPOSTProfile(metadatas, trusts, policies,receiver,ttlSeconds) {}
 
-ClubShibPOSTProfile::ClubShibPOSTProfile(const Iterator<const XMLCh*>& policies, const XMLCh* issuer)
-    : ShibPOSTProfile(policies,issuer) {}
+ClubShibPOSTProfile::ClubShibPOSTProfile(
+    const Iterator<IMetadata*>& metadatas, const Iterator<ICredentials*>& creds,
+    const Iterator<const XMLCh*>& policies, const XMLCh* issuer
+    ) : ShibPOSTProfile(metadatas,creds,policies,issuer) {}
 
 ClubShibPOSTProfile::~ClubShibPOSTProfile() {}
 
index 18a8e2e..3224917 100644 (file)
@@ -14,6 +14,7 @@ libshib_la_SOURCES = \
                     Constants.cpp \
                     CredResolvers.cpp \
                     Metadata.cpp \
+                    ReloadableXMLFile.cpp \
                     SAMLBindingFactory.cpp \
                     ShibConfig.cpp \
                     ShibPOSTProfile.cpp \
index d3cab8b..0b6791c 100644 (file)
 */
 
 #include "internal.h"
+#include <log4cpp/Category.hh>
 
 using namespace shibboleth;
 using namespace saml;
 using namespace std;
 
-OriginMetadata::OriginMetadata(const XMLCh* site) : m_mapper(NULL), m_site(NULL)
+OriginMetadata::OriginMetadata(const Iterator<IMetadata*>& metadatas, const XMLCh* site) : m_mapper(NULL), m_site(NULL)
 {
-    Iterator<IMetadata*> it=ShibConfig::getConfig().getMetadataProviders();
-    while (it.hasNext())
+    metadatas.reset();
+    while (metadatas.hasNext())
     {
-        IMetadata* i=it.next();
+        IMetadata* i=metadatas.next();
         i->lock();
         if (m_site=dynamic_cast<const IOriginSite*>(i->lookup(site)))
         {
@@ -91,10 +92,10 @@ Iterator<XSECCryptoX509*> Trust::getCertificates(const XMLCh* subject)
         m_mapper=NULL;
     }
     
-    Iterator<ITrust*> it=ShibConfig::getConfig().getTrustProviders();
-    while (it.hasNext())
+    m_trusts.reset();
+    while (m_trusts.hasNext())
     {
-        ITrust* i=it.next();
+        ITrust* i=m_trusts.next();
         i->lock();
         Iterator<XSECCryptoX509*> iter=i->getCertificates(subject);
         if (iter.size())
@@ -110,10 +111,10 @@ Iterator<XSECCryptoX509*> Trust::getCertificates(const XMLCh* subject)
 bool Trust::validate(const ISite* site, Iterator<XSECCryptoX509*> certs) const
 {
     bool ret=false;
-    Iterator<ITrust*> it=ShibConfig::getConfig().getTrustProviders();
-    while (!ret && it.hasNext())
+    m_trusts.reset();
+    while (!ret && m_trusts.hasNext())
     {
-        ITrust* i=it.next();
+        ITrust* i=m_trusts.next();
         i->lock();
         ret=i->validate(site,certs);
         i->unlock();
@@ -124,10 +125,10 @@ bool Trust::validate(const ISite* site, Iterator<XSECCryptoX509*> certs) const
 bool Trust::validate(const ISite* site, Iterator<const XMLCh*> certs) const
 {
     bool ret=false;
-    Iterator<ITrust*> it=ShibConfig::getConfig().getTrustProviders();
-    while (!ret && it.hasNext())
+    m_trusts.reset();
+    while (!ret && m_trusts.hasNext())
     {
-        ITrust* i=it.next();
+        ITrust* i=m_trusts.next();
         i->lock();
         ret=i->validate(site,certs);
         i->unlock();
@@ -138,10 +139,10 @@ bool Trust::validate(const ISite* site, Iterator<const XMLCh*> certs) const
 bool Trust::attach(const ISite* site, SSL_CTX* ctx) const
 {
     bool ret=false;
-    Iterator<ITrust*> it=ShibConfig::getConfig().getTrustProviders();
-    while (!ret && it.hasNext())
+    m_trusts.reset();
+    while (!ret && m_trusts.hasNext())
     {
-        ITrust* i=it.next();
+        ITrust* i=m_trusts.next();
         i->lock();
         ret=i->attach(site,ctx);
         i->unlock();
@@ -155,13 +156,13 @@ Trust::~Trust()
         m_mapper->unlock();
 }
 
-bool Credentials::attach(const XMLCh* subject, const ISite* relyingParty, SSL_CTX* ctx)
+bool Credentials::attach(const saml::Iterator<ICredentials*>& creds, const XMLCh* subject, const ISite* relyingParty, SSL_CTX* ctx)
 {
     bool ret=false;
-    Iterator<ICredentials*> it=ShibConfig::getConfig().getCredentialProviders();
-    while (!ret && it.hasNext())
+    creds.reset();
+    while (!ret && creds.hasNext())
     {
-        ICredentials* i=it.next();
+        ICredentials* i=creds.next();
         i->lock();
         ret=i->attach(subject,relyingParty,ctx);
         i->unlock();
@@ -170,12 +171,12 @@ bool Credentials::attach(const XMLCh* subject, const ISite* relyingParty, SSL_CT
     return ret;
 }
 
-AAP::AAP(const XMLCh* attrName, const XMLCh* attrNamespace) : m_mapper(NULL), m_rule(NULL)
+AAP::AAP(const saml::Iterator<IAAP*>& aaps, const XMLCh* attrName, const XMLCh* attrNamespace) : m_mapper(NULL), m_rule(NULL)
 {
-    Iterator<IAAP*> it=ShibConfig::getConfig().getAAPProviders();
-    while (it.hasNext())
+    aaps.reset();
+    while (aaps.hasNext())
     {
-        IAAP* i=it.next();
+        IAAP* i=aaps.next();
         i->lock();
         if (m_rule=i->lookup(attrName,attrNamespace))
         {
@@ -186,12 +187,12 @@ AAP::AAP(const XMLCh* attrName, const XMLCh* attrNamespace) : m_mapper(NULL), m_
     }
 }
 
-AAP::AAP(const char* alias) : m_mapper(NULL), m_rule(NULL)
+AAP::AAP(const saml::Iterator<IAAP*>& aaps, const char* alias) : m_mapper(NULL), m_rule(NULL)
 {
-    Iterator<IAAP*> it=ShibConfig::getConfig().getAAPProviders();
-    while (it.hasNext())
+    aaps.reset();
+    while (aaps.hasNext())
     {
-        IAAP* i=it.next();
+        IAAP* i=aaps.next();
         i->lock();
         if (m_rule=i->lookup(alias))
         {
@@ -207,3 +208,56 @@ AAP::~AAP()
     if (m_mapper)
         m_mapper->unlock();
 }
+
+void AAP::apply(const saml::Iterator<IAAP*>& aaps, const IOriginSite* originSite, saml::SAMLAssertion& assertion)
+{
+    saml::NDC("apply");
+    log4cpp::Category& log=log4cpp::Category::getInstance(SHIB_LOGCAT".AAP");
+    
+    // Check each statement.
+    Iterator<SAMLStatement*> statements=assertion.getStatements();
+    for (unsigned int scount=0; scount < statements.size();) {
+        SAMLAttributeStatement* s=dynamic_cast<SAMLAttributeStatement*>(statements[scount]);
+        if (!s)
+            continue;
+        
+        // Check each attribute.
+        Iterator<SAMLAttribute*> attrs=s->getAttributes();
+        for (unsigned int acount=0; acount < attrs.size();) {
+            SAMLAttribute* a=attrs[acount];
+
+            AAP rule(aaps,a->getName(),a->getNamespace());
+            if (rule.fail()) {
+                if (log.isWarnEnabled()) {
+                    auto_ptr_char temp(a->getName());
+                    log.warn("no rule found for attribute (%s), filtering it out",temp.get());
+                }
+                s->removeAttribute(acount);
+                continue;
+            }
+            
+            try {
+                rule->apply(originSite,*a);
+                acount++;
+            }
+            catch (SAMLException&) {
+                // The attribute is now defunct.
+                log.info("no values remain, removing attribute");
+                s->removeAttribute(acount);
+            }
+        }
+
+        try {
+            s->checkValidity();
+            scount++;
+        }
+        catch (SAMLException&) {
+            // The statement is now defunct.
+            log.info("no attributes remain, removing statement");
+            assertion.removeStatement(scount);
+        }
+    }
+    
+    // Now see if we trashed it irrevocably.
+    assertion.checkValidity();
+}
diff --git a/shib/ReloadableXMLFile.cpp b/shib/ReloadableXMLFile.cpp
new file mode 100644 (file)
index 0000000..f054ff0
--- /dev/null
@@ -0,0 +1,176 @@
+/* 
+ * The Shibboleth License, Version 1. 
+ * Copyright (c) 2002 
+ * University Corporation for Advanced Internet Development, Inc. 
+ * All rights reserved
+ * 
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice, this 
+ * list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice, 
+ * this list of conditions and the following disclaimer in the documentation 
+ * and/or other materials provided with the distribution, if any, must include 
+ * the following acknowledgment: "This product includes software developed by 
+ * the University Corporation for Advanced Internet Development 
+ * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement 
+ * may appear in the software itself, if and wherever such third-party 
+ * acknowledgments normally appear.
+ * 
+ * Neither the name of Shibboleth nor the names of its contributors, nor 
+ * Internet2, nor the University Corporation for Advanced Internet Development, 
+ * Inc., nor UCAID may be used to endorse or promote products derived from this 
+ * software without specific prior written permission. For written permission, 
+ * please contact shibboleth@shibboleth.org
+ * 
+ * Products derived from this software may not be called Shibboleth, Internet2, 
+ * UCAID, or the University Corporation for Advanced Internet Development, nor 
+ * may Shibboleth appear in their name, without prior written permission of the 
+ * University Corporation for Advanced Internet Development.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
+ * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK 
+ * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE. 
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY 
+ * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, 
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* ReloadableXMLFile.cpp - basic implementation of a reloadable XML config file
+
+   Scott Cantor
+   1/6/04
+
+   $History:$
+*/
+
+#include "internal.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <log4cpp/Category.hh>
+#include <xercesc/framework/URLInputSource.hpp>
+
+using namespace shibboleth;
+using namespace saml;
+using namespace log4cpp;
+using namespace std;
+
+ReloadableXMLFileImpl::ReloadableXMLFileImpl(const char* pathname) : m_doc(NULL)
+{
+    NDC ndc("ReloadableXMLFileImpl");
+    Category& log=Category::getInstance(SHIB_LOGCAT".ReloadableXMLFileImpl");
+
+    saml::XML::Parser p;
+    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);
+        m_doc=p.parse(dsrc);
+
+        log.infoStream() << "Loaded and parsed XML file (" << pathname << ")" << CategoryStream::ENDLINE;
+    }
+    catch (SAMLException& e)
+    {
+        log.errorStream() << "XML error while parsing configuration file: " << e.what() << CategoryStream::ENDLINE;
+        if (m_doc)
+            m_doc->release();
+        throw;
+    }
+    catch (...)
+    {
+        log.error("Unexpected error while parsing configuration file");
+        if (m_doc)
+            m_doc->release();
+        throw;
+    }
+}
+
+ReloadableXMLFileImpl::~ReloadableXMLFileImpl()
+{
+    if (m_doc)
+        m_doc->release();
+}
+
+ReloadableXMLFile::ReloadableXMLFile(const char* pathname) : m_filestamp(0), m_source(pathname), m_impl(NULL), m_lock(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_lock=RWLock::create();
+}
+
+void ReloadableXMLFile::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
+                {
+                    ReloadableXMLFileImpl* new_config=newImplementation(m_source.c_str());
+                    delete m_impl;
+                    m_impl=new_config;
+                    m_filestamp=stat_buf.st_mtime;
+                    m_lock->unlock();
+                }
+                catch(SAMLException& e)
+                {
+                    m_lock->unlock();
+                    saml::NDC ndc("lock");
+                    Category::getInstance(SHIB_LOGCAT".ReloadableXMLFile").error("failed to reload config file, sticking with what we have: %s", e.what());
+                }
+                catch(...)
+                {
+                    m_lock->unlock();
+                    saml::NDC ndc("lock");
+                    Category::getInstance(SHIB_LOGCAT".ReloadableXMLFile").error("caught an unknown exception, sticking with what we have");
+                }
+            }
+            else
+            {
+                m_lock->unlock();
+            }
+            m_lock->rdlock();
+        }
+    }
+}
+
+ReloadableXMLFileImpl* ReloadableXMLFile::getImplementation() const
+{
+    if (!m_impl)
+        m_impl=newImplementation(m_source.c_str());
+    return m_impl;
+}
index 12aff70..74a24c9 100644 (file)
 using namespace shibboleth;
 using namespace saml;
 
-SAMLBinding* SAMLBindingFactory::getInstance(const XMLCh* subject, const ISite* relyingParty, const XMLCh* protocol)
+SAMLBinding* SAMLBindingFactory::getInstance(
+    const saml::Iterator<IMetadata*>& metadatas,
+    const saml::Iterator<ITrust*>& trusts,
+    const saml::Iterator<ICredentials*>& creds,
+    const XMLCh* subject, const ISite* relyingParty, const XMLCh* protocol
+    )
 {
     if (!protocol || XMLString::compareString(protocol,SAMLBinding::SAML_SOAP_HTTPS))
         throw UnsupportedProtocolException("SAMLBindingFactory::getInstance() unable to find binding implementation for specified protocol");
 
-    return new ShibSOAPBinding(subject, relyingParty);
+    return new ShibSOAPBinding(metadatas, trusts, creds, subject, relyingParty);
 }
index 272f918..d9891f1 100644 (file)
@@ -65,11 +65,16 @@ using namespace saml;
 using namespace log4cpp;
 using namespace std;
 
+void ScopedAttribute::valueToDOM(unsigned int index, DOMElement* e) const
+{
+    SAMLAttribute::valueToDOM(index,e);
+    e->setAttributeNS(NULL,SHIB_L(Scope),m_scopes[index]);
+}
 
 ScopedAttribute::ScopedAttribute(const XMLCh* name, const XMLCh* ns, long lifetime,
                                  const saml::Iterator<const XMLCh*>& scopes,
                                  const saml::Iterator<const XMLCh*>& values)
-    : SimpleAttribute(name,ns,lifetime,values)
+    : SAMLAttribute(name,ns,NULL,lifetime,values)
 {
     if (scopes.size()!=values.size())
         throw MalformedException(SAMLException::RESPONDER,"ScopedAttribute() requires the number of scopes to equal the number of values");
@@ -78,7 +83,23 @@ ScopedAttribute::ScopedAttribute(const XMLCh* name, const XMLCh* ns, long lifeti
         m_scopes.push_back(XMLString::replicate(scopes.next()));
 }
 
-ScopedAttribute::ScopedAttribute(DOMElement* e) : SimpleAttribute(e) {}
+ScopedAttribute::ScopedAttribute(DOMElement* e) : SAMLAttribute(e)
+{
+    // Default scope comes from subject.
+    DOMNodeList* nlist=
+        static_cast<DOMElement*>(e->getParentNode())->getElementsByTagNameNS(saml::XML::SAML_NS,L(NameIdentifier));
+    if (!nlist || nlist->getLength() != 1)
+        throw MalformedException(SAMLException::RESPONDER,"ScopedAttribute() can't find saml:NameIdentifier in enclosing statement");
+    m_originSite=static_cast<DOMElement*>(nlist->item(0))->getAttributeNS(NULL,L(NameQualifier));
+
+    e=saml::XML::getFirstChildElement(e,saml::XML::SAML_NS,L(AttributeValue));
+    while (e)
+    {
+        DOMAttr* scope=e->getAttributeNodeNS(NULL,SHIB_L(Scope));
+        m_scopes.push_back(scope ? scope->getNodeValue() : &chNull);
+        e=saml::XML::getNextSiblingElement(e,saml::XML::SAML_NS,L(AttributeValue));
+    }
+}
 
 ScopedAttribute::~ScopedAttribute()
 {
@@ -99,17 +120,6 @@ ScopedAttribute::~ScopedAttribute()
     }
 }
 
-bool ScopedAttribute::addValue(DOMElement* e)
-{
-    if (SAMLAttribute::addValue(e))
-    {
-        DOMAttr* scope=e->getAttributeNodeNS(NULL,SHIB_L(Scope));
-        m_scopes.push_back(scope ? scope->getNodeValue() : &chNull);
-        return true;
-    }
-    return false;
-}
-
 Iterator<const XMLCh*> ScopedAttribute::getValues() const
 {
     static XMLCh at[]={chAt, chNull};
@@ -146,27 +156,28 @@ Iterator<string> ScopedAttribute::getSingleByteValues() const
     return Iterator<string>(m_sbValues);
 }
 
-SAMLObject* ScopedAttribute::clone() const
+void ScopedAttribute::setValues(const Iterator<const XMLCh*>& values)
 {
-    return new ScopedAttribute(m_name,m_namespace,m_lifetime,m_scopes,m_values);
+    throw SAMLException("unsupported operation");
 }
 
-DOMNode* ScopedAttribute::toDOM(DOMDocument* doc,bool xmlns) const
+void ScopedAttribute::addValue(const XMLCh* value)
 {
-    SimpleAttribute::toDOM(doc,xmlns);
+    throw SAMLException("unsupported operation");
+}
 
-    int i=0;
-    DOMNode* n=m_root->getFirstChild();
-    while (n)
-    {
-        if (n->getNodeType()==DOMNode::ELEMENT_NODE)
-        {
-            static_cast<DOMElement*>(n)->setAttributeNS(NULL,SHIB_L(Scope),m_scopes[i]);
-            i++;
-        }
-        n=n->getNextSibling();
+void ScopedAttribute::removeValue(unsigned int index)
+{
+    SAMLAttribute::removeValue(index);
+    
+    if (m_bOwnStrings) {
+        XMLCh* p=const_cast<XMLCh*>(m_scopes[index]);
+        XMLString::release(&p);
     }
-
-    return m_root;
+    m_scopes.erase(m_scopes.begin()+index);
 }
 
+SAMLObject* ScopedAttribute::clone() const
+{
+    return new ScopedAttribute(m_name,m_namespace,m_lifetime,m_scopes,m_values);
+}
index 552eaa6..0ad1415 100644 (file)
@@ -95,7 +95,7 @@ extern "C" SAMLAttribute* ShibAttributeFactory(DOMElement* e)
         n=n->getNextSibling();
     if (n && static_cast<DOMElement*>(n)->hasAttributeNS(NULL,SHIB_L(Scope)))
         return new ScopedAttribute(e);
-    return new SimpleAttribute(e);
+    return new SAMLAttribute(e);
 }
 
 
@@ -109,6 +109,8 @@ bool ShibInternalConfig::init()
     // Register extension schema.
     saml::XML::registerSchema(XML::SHIB_NS,XML::SHIB_SCHEMA_ID);
 
+    SAMLAttribute::setFactory(&ShibAttributeFactory);
+
     // Register metadata factories (some duplicates for backward-compatibility)
     regFactory("edu.internet2.middleware.shibboleth.metadata.XML",&XMLMetadataFactory);
     regFactory("edu.internet2.middleware.shibboleth.metadata.provider.XML",&XMLMetadataFactory);
@@ -119,23 +121,10 @@ bool ShibInternalConfig::init()
     regFactory("edu.internet2.middleware.shibboleth.creds.provider.KeyInfoResolver",&KeyInfoResolverFactory);
     regFactory("edu.internet2.middleware.shibboleth.target.AAP.XML",&XMLAAPFactory);
     regFactory("edu.internet2.middleware.shibboleth.target.AAP.provider.XML",&XMLAAPFactory);
-    regFactory("edu.internet2.middleware.shibboleth.target.AttributeFactory",&ShibAttributeFactory);
 
     return true;
 }
 
-void ShibInternalConfig::term()
-{
-    for (vector<IMetadata*>::iterator i=m_providers.begin(); i!=m_providers.end(); i++)
-        delete *i;
-    for (vector<ITrust*>::iterator j=m_trust_providers.begin(); j!=m_trust_providers.end(); j++)
-        delete *j;
-    for (vector<ICredentials*>::iterator k=m_cred_providers.begin(); k!=m_cred_providers.end(); k++)
-        delete *k;
-    for (vector<IAAP*>::iterator l=m_aap_providers.begin(); l!=m_aap_providers.end(); l++)
-        delete *l;
-}
-
 void ShibInternalConfig::regFactory(const char* type, MetadataFactory* factory)
 {
     if (type && factory)
@@ -169,12 +158,6 @@ void ShibInternalConfig::regFactory(const char* type, AAPFactory* factory)
         m_aapFactoryMap[type]=factory;
 }
 
-void ShibInternalConfig::regFactory(const char* type, SAMLAttributeFactory* factory)
-{
-    if (type && factory)
-        m_attrFactoryMap[type]=factory;
-}
-
 void ShibInternalConfig::unregFactory(const char* type)
 {
     if (type)
@@ -187,87 +170,64 @@ void ShibInternalConfig::unregFactory(const char* type)
     }
 }
 
-SAMLAttributeFactory* ShibInternalConfig::getAttributeFactory(const char* type) const
+IMetadata* ShibInternalConfig::newMetadata(const char* type, const char* source) const
 {
-    AttributeFactoryMap::const_iterator i =
-        m_attrFactoryMap.find((type && *type) ? type : "edu.internet2.middleware.shibboleth.target.AttributeFactory");
-    if (i==m_attrFactoryMap.end())
+    MetadataFactoryMap::const_iterator i=m_metadataFactoryMap.find(type);
+    if (i==m_metadataFactoryMap.end())
     {
-        NDC ndc("getAttributeFactory");
-        Category::getInstance(SHIB_LOGCAT".ShibInternalConfig").error("unknown attribute factory: %s",type);
+        NDC ndc("newMetadata");
+        Category::getInstance(SHIB_LOGCAT".ShibInternalConfig").error("unknown metadata type: %s",type);
         return NULL;
     }
-    return i->second;
+    return i->second(source);
 }
 
-CredResolverFactory* ShibInternalConfig::getCredResolverFactory(const char* type) const
+ITrust* ShibInternalConfig::newTrust(const char* type, const char* source) const
 {
-    CredResolverFactoryMap::const_iterator i=m_credResolverFactoryMap.find(type);
-    if (i==m_credResolverFactoryMap.end())
+    TrustFactoryMap::const_iterator i=m_trustFactoryMap.find(type);
+    if (i==m_trustFactoryMap.end())
     {
-        NDC ndc("getCredResolverFactory");
-        Category::getInstance(SHIB_LOGCAT".ShibInternalConfig").error("unknown cred resolver factory: %s",type);
+        NDC ndc("newTrust");
+        Category::getInstance(SHIB_LOGCAT".ShibInternalConfig").error("unknown trust type: %s",type);
         return NULL;
     }
-    return i->second;
+    return i->second(source);
 }
 
-bool ShibInternalConfig::addMetadata(const char* type, const char* source)
+ICredentials* ShibInternalConfig::newCredentials(const char* type, const char* source) const
 {
-    saml::NDC ndc("addMetadata");
-
-    bool ret=false;
-    try
+    CredentialsFactoryMap::const_iterator i=m_credFactoryMap.find(type);
+    if (i==m_credFactoryMap.end())
     {
-        MetadataFactoryMap::const_iterator i=m_metadataFactoryMap.find(type);
-        if (i!=m_metadataFactoryMap.end())
-        {
-            m_providers.push_back((i->second)(source));
-            ret=true;
-        }
-        else
-        {
-            TrustFactoryMap::const_iterator j=m_trustFactoryMap.find(type);
-            if (j!=m_trustFactoryMap.end())
-            {
-                m_trust_providers.push_back((j->second)(source));
-                ret=true;
-            }
-            else
-            {
-                CredentialsFactoryMap::const_iterator k=m_credFactoryMap.find(type);
-                if (k!=m_credFactoryMap.end())
-                {
-                    m_cred_providers.push_back((k->second)(source));
-                    ret=true;
-                }
-                else
-                {
-                    AAPFactoryMap::const_iterator l=m_aapFactoryMap.find(type);
-                    if (l!=m_aapFactoryMap.end())
-                    {
-                        m_aap_providers.push_back((l->second)(source));
-                        ret=true;
-                    }
-                    else
-                        throw MetadataException("ShibConfig::addMetadata() unable to locate a metadata factory of the requested type");
-                }
-            }
-        }
+        NDC ndc("newCredentials");
+        Category::getInstance(SHIB_LOGCAT".ShibInternalConfig").error("unknown credentials type: %s",type);
+        return NULL;
     }
-    catch (SAMLException& e)
+    return i->second(source);
+}
+
+IAAP* ShibInternalConfig::newAAP(const char* type, const char* source) const
+{
+    AAPFactoryMap::const_iterator i=m_aapFactoryMap.find(type);
+    if (i==m_aapFactoryMap.end())
     {
-        Category::getInstance(SHIB_LOGCAT".ShibConfig").error(
-            "failed to add %s provider to system using source '%s': %s", type, source, e.what()
-            );
+        NDC ndc("newAAP");
+        Category::getInstance(SHIB_LOGCAT".ShibInternalConfig").error("unknown AAP type: %s",type);
+        return NULL;
     }
-    catch (...)
+    return i->second(source);
+}
+
+ICredResolver* ShibInternalConfig::newCredResolver(const char* type, const DOMElement* source) const
+{
+    CredResolverFactoryMap::const_iterator i=m_credResolverFactoryMap.find(type);
+    if (i==m_credResolverFactoryMap.end())
     {
-        Category::getInstance(SHIB_LOGCAT".ShibConfig").error(
-            "failed to add %s provider to system using source '%s': unknown exception", type, source
-            );
+        NDC ndc("newCredResolver");
+        Category::getInstance(SHIB_LOGCAT".ShibInternalConfig").error("unknown cred resolver type: %s",type);
+        return NULL;
     }
-    return ret;
+    return i->second(source);
 }
 
 ShibConfig& ShibConfig::getConfig()
index 5583ce6..432091e 100644 (file)
@@ -65,42 +65,34 @@ using namespace shibboleth;
 using namespace saml;
 using namespace std;
 
-ShibPOSTProfile::ShibPOSTProfile(const Iterator<const XMLCh*>& policies, const XMLCh* receiver, int ttlSeconds)
-    : m_ttlSeconds(ttlSeconds), m_algorithm(SIGNATURE_RSA), m_issuer(NULL)
+static Iterator<ITrust*> emptyTrusts;
+static Iterator<ICredentials*> emptyCreds;
+
+ShibPOSTProfile::ShibPOSTProfile(
+    const Iterator<IMetadata*>& metadatas, const Iterator<ITrust*>& trusts,
+    const Iterator<const XMLCh*>& policies, const XMLCh* receiver, int ttlSeconds
+    )
+    : m_ttlSeconds(ttlSeconds), m_algorithm(SIGNATURE_RSA), m_issuer(NULL), m_receiver(receiver),
+        m_metadatas(metadatas), m_trusts(trusts), m_policies(policies), m_creds(emptyCreds)
 {
     if (!receiver || !*receiver || ttlSeconds <= 0)
         throw SAMLException(SAMLException::REQUESTER, "ShibPOSTProfile() found a null or invalid argument");
-
-    m_receiver = XMLString::replicate(receiver);
-
-    while (policies.hasNext())
-        m_policies.push_back(XMLString::replicate(policies.next()));
 }
 
-ShibPOSTProfile::ShibPOSTProfile(const Iterator<const XMLCh*>& policies, const XMLCh* issuer)
-    : m_ttlSeconds(0), m_algorithm(SIGNATURE_RSA), m_receiver(NULL)
+ShibPOSTProfile::ShibPOSTProfile(
+    const saml::Iterator<IMetadata*>& metadatas, const saml::Iterator<ICredentials*>& creds,
+    const Iterator<const XMLCh*>& policies, const XMLCh* issuer
+    )
+    : m_ttlSeconds(0), m_algorithm(SIGNATURE_RSA), m_receiver(NULL), m_issuer(issuer),
+        m_policies(policies), m_metadatas(metadatas), m_creds(creds), m_trusts(emptyTrusts)
 {
     if (!issuer || !*issuer)
         throw SAMLException(SAMLException::REQUESTER, "ShibPOSTProfile() found a null or invalid argument");
-
-    m_issuer = XMLString::replicate(issuer);
-
-    while (policies.hasNext())
-        m_policies.push_back(XMLString::replicate(policies.next()));
-}
-
-ShibPOSTProfile::~ShibPOSTProfile()
-{
-    delete[] m_issuer;
-    delete[] m_receiver;
-
-    for (vector<const XMLCh*>::iterator i=m_policies.begin(); i!=m_policies.end(); i++)
-        delete[] const_cast<XMLCh*>(*i);
 }
 
 const SAMLAssertion* ShibPOSTProfile::getSSOAssertion(const SAMLResponse& r)
 {
-    return SAMLPOSTProfile::getSSOAssertion(r,Iterator<const XMLCh*>(m_policies));
+    return SAMLPOSTProfile::getSSOAssertion(r,m_policies);
 }
 
 const SAMLAuthenticationStatement* ShibPOSTProfile::getSSOStatement(const SAMLAssertion& a)
@@ -168,7 +160,7 @@ SAMLResponse* ShibPOSTProfile::accept(const XMLByte* buf, XMLCh** originSitePtr)
     
         // Is this a trusted HS?
         const IAuthority* hs=NULL;
-        OriginMetadata mapper(originSite);
+        OriginMetadata mapper(m_metadatas,originSite);
         Iterator<const IAuthority*> hsi=mapper.fail() ? Iterator<const IAuthority*>() : mapper->getHandleServices();
         bool bFound = false;
         while (!bFound && hsi.hasNext())
@@ -180,7 +172,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");
     
-        Trust t;
+        Trust t(m_trusts);
         Iterator<XSECCryptoX509*> certs=t.getCertificates(hs->getName());
         Iterator<XSECCryptoX509*> certs2=t.getCertificates(originSite);
     
@@ -300,13 +292,13 @@ void ShibPOSTProfile::verifySignature(
             certs.push_back(obj.getX509Certificate(i));
 
         // Compare the name in the end entity certificate to the signer's name.
-        auto_ptr<char> temp(XMLString::transcode(certs[0]));
+        auto_ptr_char temp(certs[0]);
         X509* x=B64_to_X509(temp.get());
         if (!x)
             throw TrustException("ShibPOSTProfile::verifySignature() unable to decode X.509 signing certificate");
 
         bool match=false;
-        auto_ptr<char> sn(XMLString::transcode(signerName));
+        auto_ptr_char sn(signerName);
 
         char data[256];
         X509_NAME* subj;
@@ -357,7 +349,7 @@ void ShibPOSTProfile::verifySignature(
             throw TrustException("ShibPOSTProfile::verifySignature() cannot match CN or subjectAltName against signer");
 
         // Ask the site to determine the trustworthiness of the certificate.
-        if (!originSite->validate(certs))
+        if (!originSite->validate(m_trusts,certs))
             throw TrustException("ShibPOSTProfile::verifySignature() cannot validate the provided signing certificate(s)");
     }
 }
index 79661ed..1be5019 100644 (file)
@@ -61,12 +61,18 @@ using namespace shibboleth;
 using namespace saml;
 using namespace std;
 
-ShibPOSTProfile* ShibPOSTProfileFactory::getInstance(const Iterator<const XMLCh*>& policies, const XMLCh* receiver, int ttlSeconds)
+ShibPOSTProfile* ShibPOSTProfileFactory::getInstance(
+    const Iterator<IMetadata*>& metadatas, const Iterator<ITrust*>& trusts,
+    const Iterator<const XMLCh*>& policies, const XMLCh* receiver, int ttlSeconds
+    )
 {
-    return new ClubShibPOSTProfile(policies,receiver,ttlSeconds);
+    return new ClubShibPOSTProfile(metadatas,trusts,policies,receiver,ttlSeconds);
 }
 
-ShibPOSTProfile* ShibPOSTProfileFactory::getInstance(const Iterator<const XMLCh*>& policies, const XMLCh* issuer)
+ShibPOSTProfile* ShibPOSTProfileFactory::getInstance(
+    const Iterator<IMetadata*>& metadatas, const Iterator<ICredentials*>& creds,
+    const Iterator<const XMLCh*>& policies, const XMLCh* issuer
+    )
 {
-    return new ClubShibPOSTProfile(policies,issuer);
+    return new ClubShibPOSTProfile(metadatas,creds,policies,issuer);
 }
index 72cb63b..cde6083 100644 (file)
@@ -78,13 +78,13 @@ bool shibboleth::ssl_ctx_callback(void* ssl_ctx, void* userptr)
     try
     {
         ShibSOAPBinding* b = reinterpret_cast<ShibSOAPBinding*>(userptr);
-        if (!Credentials::attach(b->m_subject, b->m_relyingParty, reinterpret_cast<ssl_ctx_st*>(ssl_ctx)))
+        if (!Credentials::attach(b->m_creds, b->m_subject, b->m_relyingParty, reinterpret_cast<ssl_ctx_st*>(ssl_ctx)))
         {
             NDC("ssl_ctx_callback");
             Category::getInstance(SHIB_LOGCAT".ShibSOAPBinding").warn("found no appropriate credentials to attach, request will be anonymous");
         }
 
-        Trust t;
+        Trust t(b->m_trusts);
         if (!t.attach(b->m_relyingParty, reinterpret_cast<ssl_ctx_st*>(ssl_ctx)))
         {
             NDC("ssl_ctx_callback");
diff --git a/shib/SimpleAttribute.cpp b/shib/SimpleAttribute.cpp
deleted file mode 100644 (file)
index 1ecbe91..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * The Shibboleth License, Version 1.
- * Copyright (c) 2002
- * University Corporation for Advanced Internet Development, Inc.
- * All rights reserved
- *
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution, if any, must include
- * the following acknowledgment: "This product includes software developed by
- * the University Corporation for Advanced Internet Development
- * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement
- * may appear in the software itself, if and wherever such third-party
- * acknowledgments normally appear.
- *
- * Neither the name of Shibboleth nor the names of its contributors, nor
- * Internet2, nor the University Corporation for Advanced Internet Development,
- * Inc., nor UCAID may be used to endorse or promote products derived from this
- * software without specific prior written permission. For written permission,
- * please contact shibboleth@shibboleth.org
- *
- * Products derived from this software may not be called Shibboleth, Internet2,
- * UCAID, or the University Corporation for Advanced Internet Development, nor
- * may Shibboleth appear in their name, without prior written permission of the
- * University Corporation for Advanced Internet Development.
- *
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
- * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK
- * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY
- * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-
-/* SimpleAttribute.cpp - simple attribute implementation with AAP-support
-
-   Scott Cantor
-   12/19/02
-
-   $History:$
-*/
-
-#include "internal.h"
-
-using namespace shibboleth;
-
-SimpleAttribute::SimpleAttribute(const XMLCh* name, const XMLCh* ns, long lifetime, const saml::Iterator<const XMLCh*>& values)
-    : SAMLAttribute(name,ns,&Constants::SHIB_ATTRIBUTE_VALUE_TYPE,lifetime,values), m_originSite(NULL) {}
-
-SimpleAttribute::SimpleAttribute(DOMElement* e) : SAMLAttribute(e)
-{
-    // Default scope comes from subject.
-    DOMNodeList* nlist=
-        static_cast<DOMElement*>(e->getParentNode())->getElementsByTagNameNS(saml::XML::SAML_NS,L(NameIdentifier));
-    if (!nlist || nlist->getLength() != 1)
-        throw saml::MalformedException(saml::SAMLException::RESPONDER,"SimpleAttribute() can't find saml:NameIdentifier in enclosing statement");
-    m_originSite=static_cast<DOMElement*>(nlist->item(0))->getAttributeNS(NULL,L(NameQualifier));
-}
-
-SimpleAttribute::~SimpleAttribute() {}
-
-saml::SAMLObject* SimpleAttribute::clone() const
-{
-    SimpleAttribute* dest=new SimpleAttribute(m_name,m_namespace,m_lifetime);
-    dest->m_values.assign(m_values.begin(),m_values.end());
-    return dest;
-}
-
-bool SimpleAttribute::accept(DOMElement* e) const
-{
-    AAP aap(m_name,m_namespace);
-    return aap.fail() ? false : aap->accept(m_originSite,e);
-}
index e9a0cd8..e539463 100644 (file)
@@ -72,7 +72,7 @@ using namespace std;
 
 namespace shibboleth {
     
-    class XMLCredentialsImpl
+    class XMLCredentialsImpl : public ReloadableXMLFileImpl
     {
     public:
         XMLCredentialsImpl(const char* pathname);
@@ -93,31 +93,40 @@ namespace shibboleth {
         vector<KeyUse*> m_keyuses;
         typedef multimap<pair<const XMLCh*,bool>,KeyUse*> BindingMap;
         BindingMap m_bindings;
-        
-        DOMDocument* m_doc;
     };
 
-    class XMLCredentials : public ICredentials
+    class XMLCredentials : public ICredentials, public ReloadableXMLFile
     {
     public:
-        XMLCredentials(const char* pathname);
-        ~XMLCredentials() { delete m_lock; delete m_impl; }
+        XMLCredentials(const char* pathname) : ReloadableXMLFile(pathname) {}
+        ~XMLCredentials() {}
+        
         bool attach(const XMLCh* subject, const ISite* relyingParty, SSL_CTX* ctx) const;
 
-    private:
-        void lock();
-        void unlock() { m_lock->unlock(); }
-        std::string m_source;
-        time_t m_filestamp;
-        RWLock* m_lock;
-        XMLCredentialsImpl* m_impl;
+    protected:
+        virtual ReloadableXMLFileImpl* newImplementation(const char* pathname) const;
     };
 
 }
 
 extern "C" ICredentials* XMLCredentialsFactory(const char* source)
 {
-    return new XMLCredentials(source);
+    XMLCredentials* creds=new XMLCredentials(source);
+    try
+    {
+        creds->getImplementation();
+    }
+    catch (...)
+    {
+        delete creds;
+        throw;
+    }
+    return creds;    
+}
+
+ReloadableXMLFileImpl* XMLCredentials::newImplementation(const char* pathname) const
+{
+    return new XMLCredentialsImpl(pathname);
 }
 
 XMLCredentialsImpl::KeyUse::KeyUse(resolvermap_t& resolverMap, const XMLCh* keyref, const XMLCh* certref) : m_key(NULL), m_cert(NULL)
@@ -138,21 +147,13 @@ XMLCredentialsImpl::KeyUse::KeyUse(resolvermap_t& resolverMap, const XMLCh* keyr
     }
 }
 
-XMLCredentialsImpl::XMLCredentialsImpl(const char* pathname) : m_doc(NULL)
+XMLCredentialsImpl::XMLCredentialsImpl(const char* pathname) : ReloadableXMLFileImpl(pathname)
 {
     NDC ndc("XMLCredentialsImpl");
     Category& log=Category::getInstance(SHIB_LOGCAT".XMLCredentialsImpl");
 
-    saml::XML::Parser p;
     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);
-        m_doc=p.parse(dsrc);
-
-        log.infoStream() << "Loaded and parsed creds file (" << pathname << ")" << CategoryStream::ENDLINE;
-
         DOMElement* e = m_doc->getDocumentElement();
         if (XMLString::compareString(XML::SHIB_NS,e->getNamespaceURI()) ||
             XMLString::compareString(SHIB_L(Credentials),e->getLocalName()))
@@ -165,24 +166,24 @@ XMLCredentialsImpl::XMLCredentialsImpl(const char* pathname) : m_doc(NULL)
         DOMElement* child=saml::XML::getFirstChildElement(e);
         while (!saml::XML::isElementNamed(child,XML::SHIB_NS,SHIB_L(KeyUse)))
         {
-            CredResolverFactory* factory=NULL;
+            string cr_type;
             auto_ptr<char> id(XMLString::transcode(child->getAttributeNS(NULL,SHIB_L(Id))));
             
             if (saml::XML::isElementNamed(child,XML::SHIB_NS,SHIB_L(FileCredResolver)))
-                factory=ShibConfig::getConfig().getCredResolverFactory("edu.internet2.middleware.shibboleth.creds.provider.FileCredResolver");
+                cr_type="edu.internet2.middleware.shibboleth.creds.provider.FileCredResolver";
             else if (saml::XML::isElementNamed(child,saml::XML::XMLSIG_NS,L(KeyInfo)))
-                factory=ShibConfig::getConfig().getCredResolverFactory("edu.internet2.middleware.shibboleth.creds.provider.KeyInfoResolver");
+                cr_type="edu.internet2.middleware.shibboleth.creds.provider.KeyInfoResolver";
             else if (saml::XML::isElementNamed(child,XML::SHIB_NS,SHIB_L(CustomCredResolver)))
             {
-                auto_ptr<char> c(XMLString::transcode(child->getAttributeNS(NULL,SHIB_L(Class))));
-                factory=ShibConfig::getConfig().getCredResolverFactory(c.get());
+                auto_ptr_char c(child->getAttributeNS(NULL,SHIB_L(Class)));
+                cr_type=c.get();
             }
             
-            if (factory)
+            if (!cr_type.empty())
             {
                 try
                 {
-                    ICredResolver* cr=(*factory)(child);
+                    ICredResolver* cr=ShibConfig::getConfig().newCredResolver(cr_type.c_str(),child);
                     m_resolverMap[id.get()]=cr;
                 }
                 catch (SAMLException& e)
@@ -251,7 +252,7 @@ XMLCredentialsImpl::XMLCredentialsImpl(const char* pathname) : m_doc(NULL)
     }
     catch (SAMLException& e)
     {
-        log.errorStream() << "XML error while parsing creds configuration: " << e.what() << CategoryStream::ENDLINE;
+        log.errorStream() << "Error while parsing creds configuration: " << e.what() << CategoryStream::ENDLINE;
         for (vector<KeyUse*>::iterator i=m_keyuses.begin(); i!=m_keyuses.end(); i++)
             delete (*i);
         for (resolvermap_t::iterator j=m_resolverMap.begin(); j!=m_resolverMap.end(); j++)
@@ -260,6 +261,7 @@ XMLCredentialsImpl::XMLCredentialsImpl(const char* pathname) : m_doc(NULL)
             m_doc->release();
         throw;
     }
+#ifndef _DEBUG
     catch (...)
     {
         log.error("Unexpected error while parsing creds configuration");
@@ -271,6 +273,7 @@ XMLCredentialsImpl::XMLCredentialsImpl(const char* pathname) : m_doc(NULL)
             m_doc->release();
         throw;
     }
+#endif
 }
 
 XMLCredentialsImpl::~XMLCredentialsImpl()
@@ -279,81 +282,15 @@ XMLCredentialsImpl::~XMLCredentialsImpl()
         delete (*i);
     for (resolvermap_t::iterator j=m_resolverMap.begin(); j!=m_resolverMap.end(); j++)
         delete j->second;
-    if (m_doc)
-        m_doc->release();
-}
-
-XMLCredentials::XMLCredentials(const char* pathname) : m_filestamp(0), m_source(pathname), 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 XMLCredentialsImpl(pathname);
-    m_lock=RWLock::create();
-}
-
-void XMLCredentials::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
-                {
-                    XMLCredentialsImpl* new_mapper=new XMLCredentialsImpl(m_source.c_str());
-                    delete m_impl;
-                    m_impl=new_mapper;
-                    m_filestamp=stat_buf.st_mtime;
-                    m_lock->unlock();
-                }
-                catch(SAMLException& e)
-                {
-                    m_lock->unlock();
-                    saml::NDC ndc("lock");
-                    Category::getInstance(SHIB_LOGCAT".XMLCredentials").error("failed to reload credentials metadata, sticking with what we have: %s", e.what());
-                }
-                catch(...)
-                {
-                    m_lock->unlock();
-                    saml::NDC ndc("lock");
-                    Category::getInstance(SHIB_LOGCAT".XMLCredentials").error("caught an unknown exception, sticking with what we have");
-                }
-            }
-            else
-            {
-                m_lock->unlock();
-            }
-            m_lock->rdlock();
-        }
-    }
 }
 
-
 bool XMLCredentials::attach(const XMLCh* subject, const ISite* relyingParty, SSL_CTX* ctx) const
 {
     NDC ndc("attach");
 
     // Use the matching bindings.
-    for (XMLCredentialsImpl::BindingMap::const_iterator i=m_impl->m_bindings.begin(); i!=m_impl->m_bindings.end(); i++)
+    XMLCredentialsImpl* impl=dynamic_cast<XMLCredentialsImpl*>(getImplementation());
+    for (XMLCredentialsImpl::BindingMap::const_iterator i=impl->m_bindings.begin(); i!=impl->m_bindings.end(); i++)
     {
         bool match=false;
         
index af1cc41..3a1194f 100644 (file)
@@ -71,7 +71,7 @@ using namespace std;
 
 namespace shibboleth {
 
-    class XMLMetadataImpl
+    class XMLMetadataImpl : public ReloadableXMLFileImpl
     {
     public:
         XMLMetadataImpl(const char* pathname);
@@ -81,43 +81,44 @@ namespace shibboleth {
         {
         public:
             ContactInfo(ContactType type, const XMLCh* name, const XMLCh* email)
-                : m_type(type), m_name(XMLString::transcode(name)), m_email(XMLString::transcode(email)) {}
+                : m_type(type), m_name(name), m_email(email) {}
         
             ContactType getType() const { return m_type; }
-            const char* getName() const { return m_name.get(); }            
+            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;
+            auto_ptr_char m_name, m_email;
         };
         
         class Authority : public IAuthority
         {
         public:
-            Authority(const XMLCh* name, const XMLCh* url) : m_name(name), m_url(XMLString::transcode(url)) {}
+            Authority(const XMLCh* name, const XMLCh* url) : m_name(name), m_url(url) {}
         
             const XMLCh* getName() const { return m_name; }
             const char* getURL() const { return m_url.get(); }
         
         private:
             const XMLCh* m_name;
-            auto_ptr<char> m_url;
+            auto_ptr_char m_url;
         };
     
         class OriginSite : public IOriginSite
         {
         public:
-            OriginSite(const XMLCh* name, const XMLCh* errorURL)
-                : m_name(name), m_errorURL(XMLString::transcode(errorURL)) {}
+            OriginSite(const XMLCh* name, const XMLCh* errorURL) : m_name(name), m_errorURL(errorURL) {}
             ~OriginSite();
         
             const XMLCh* getName() const {return m_name;}
             Iterator<const XMLCh*> getGroups() const {return m_groups;}
             Iterator<const IContactInfo*> getContacts() const {return m_contacts;}
             const char* getErrorURL() const {return m_errorURL.get();}
-            bool validate(Iterator<XSECCryptoX509*> certs) const {Trust t; return t.validate(this,certs);}
-            bool validate(Iterator<const XMLCh*> certs) const {Trust t; return t.validate(this,certs);}
+            bool validate(const saml::Iterator<ITrust*>& trusts, const Iterator<XSECCryptoX509*>& certs) const
+                {Trust t(trusts); return t.validate(this,certs);}
+            bool validate(const saml::Iterator<ITrust*>& trusts, const Iterator<const XMLCh*>& certs) const
+                {Trust t(trusts); return t.validate(this,certs);}
             Iterator<const IAuthority*> getHandleServices() const {return m_handleServices;}
             Iterator<const IAuthority*> getAttributeAuthorities() const {return m_attributes;}
             Iterator<std::pair<const XMLCh*,bool> > getSecurityDomains() const {return m_domains;}
@@ -125,7 +126,7 @@ namespace shibboleth {
         private:
             friend class XMLMetadataImpl;
             const XMLCh* m_name;
-            auto_ptr<char> m_errorURL;
+            auto_ptr_char m_errorURL;
             vector<const IContactInfo*> m_contacts;
             vector<const IAuthority*> m_handleServices;
             vector<const IAuthority*> m_attributes;
@@ -139,30 +140,39 @@ namespace shibboleth {
         typedef map<string,OriginSite*> sitemap_t;
     #endif
         sitemap_t m_sites;
-        DOMDocument* m_doc;
     };
 
-    class XMLMetadata : public IMetadata
+    class XMLMetadata : public IMetadata, public ReloadableXMLFile
     {
     public:
-        XMLMetadata(const char* pathname);
-        ~XMLMetadata() { delete m_lock; delete m_impl; }
+        XMLMetadata(const char* pathname) : ReloadableXMLFile(pathname) {}
+        ~XMLMetadata() {}
 
-        void lock();
-        void unlock() { m_lock->unlock(); }
         const ISite* lookup(const XMLCh* site) const;
-
-    private:
-        std::string m_source;
-        time_t m_filestamp;
-        RWLock* m_lock;
-        XMLMetadataImpl* m_impl;
+        
+    protected:
+        virtual ReloadableXMLFileImpl* newImplementation(const char* pathname) const;
     };
 }
 
 extern "C" IMetadata* XMLMetadataFactory(const char* source)
 {
-    return new XMLMetadata(source);
+    XMLMetadata* m=new XMLMetadata(source);
+    try
+    {
+        m->getImplementation();
+    }
+    catch (...)
+    {
+        delete m;
+        throw;
+    }
+    return m;    
+}
+
+ReloadableXMLFileImpl* XMLMetadata::newImplementation(const char* pathname) const
+{
+    return new XMLMetadataImpl(pathname);
 }
 
 XMLMetadataImpl::OriginSite::~OriginSite()
@@ -175,21 +185,13 @@ XMLMetadataImpl::OriginSite::~OriginSite()
         delete const_cast<IAuthority*>(*k);
 }
 
-XMLMetadataImpl::XMLMetadataImpl(const char* pathname) : m_doc(NULL)
+XMLMetadataImpl::XMLMetadataImpl(const char* pathname) : ReloadableXMLFileImpl(pathname)
 {
     NDC ndc("XMLMetadataImpl");
     Category& log=Category::getInstance(SHIB_LOGCAT".XMLMetadataImpl");
 
-    saml::XML::Parser p;
     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);
-        m_doc=p.parse(dsrc);
-
-        log.infoStream() << "Loaded and parsed site file (" << pathname << ")" << CategoryStream::ENDLINE;
-
         DOMElement* e = m_doc->getDocumentElement();
         if (XMLString::compareString(XML::SHIB_NS,e->getNamespaceURI()) ||
             XMLString::compareString(XML::Literals::SiteGroup,e->getLocalName()))
@@ -288,7 +290,7 @@ XMLMetadataImpl::XMLMetadataImpl(const char* pathname) : m_doc(NULL)
     }
     catch (SAMLException& e)
     {
-        log.errorStream() << "XML error while parsing site configuration: " << e.what() << CategoryStream::ENDLINE;
+        log.errorStream() << "Error while parsing site configuration: " << e.what() << CategoryStream::ENDLINE;
         for (sitemap_t::iterator i=m_sites.begin(); i!=m_sites.end(); i++)
             delete i->second;
         if (m_doc)
@@ -310,81 +312,16 @@ XMLMetadataImpl::~XMLMetadataImpl()
 {
     for (sitemap_t::iterator i=m_sites.begin(); i!=m_sites.end(); i++)
         delete i->second;
-    if (m_doc)
-        m_doc->release();
-}
-
-XMLMetadata::XMLMetadata(const char* pathname) : m_filestamp(0), m_source(pathname), 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 XMLMetadataImpl(pathname);
-    m_lock=RWLock::create();
-}
-
-void XMLMetadata::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
-                {
-                    XMLMetadataImpl* new_mapper=new XMLMetadataImpl(m_source.c_str());
-                    delete m_impl;
-                    m_impl=new_mapper;
-                    m_filestamp=stat_buf.st_mtime;
-                    m_lock->unlock();
-                }
-                catch(SAMLException& e)
-                {
-                    m_lock->unlock();
-                    saml::NDC ndc("lock");
-                    Category::getInstance(SHIB_LOGCAT".XMLMetadata").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".XMLMetadata").error("caught an unknown exception, sticking with what we have");
-                }
-            }
-            else
-            {
-                m_lock->unlock();
-            }
-            m_lock->rdlock();
-        }
-    }
 }
 
 const ISite* XMLMetadata::lookup(const XMLCh* site) const
 {
+    XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
 #ifdef HAVE_GOOD_STL
-    XMLMetadataImpl::sitemap_t::const_iterator i=m_impl->m_sites.find(site);
+    XMLMetadataImpl::sitemap_t::const_iterator i=impl->m_sites.find(site);
 #else
     auto_ptr<char> temp(XMLString::transcode(site));
-    XMLMetadataImpl::sitemap_t::const_iterator i=m_impl->m_sites.find(temp.get());
+    XMLMetadataImpl::sitemap_t::const_iterator i=impl->m_sites.find(temp.get());
 #endif
-    return (i==m_impl->m_sites.end()) ? NULL : i->second;
+    return (i==impl->m_sites.end()) ? NULL : i->second;
 }
index c0a6b1b..b106bae 100644 (file)
@@ -82,7 +82,7 @@ int verify_callback(int ok, X509_STORE_CTX* store)
 
 namespace shibboleth {
 
-    class XMLTrustImpl
+    class XMLTrustImpl : public ReloadableXMLFileImpl
     {
     public:
         XMLTrustImpl(const char* pathname);
@@ -104,35 +104,44 @@ namespace shibboleth {
         vector<KeyAuthority*> m_keyauths;
         typedef map<pair<const XMLCh*,bool>,KeyAuthority*> BindingMap;
         BindingMap m_bindings;
-        
-        DOMDocument* m_doc;
     };
 
-    class XMLTrust : public ITrust
+    class XMLTrust : public ITrust, public ReloadableXMLFile
     {
     public:
-        XMLTrust(const char* pathname);
-        ~XMLTrust() { delete m_lock; delete m_impl; }
+        XMLTrust(const char* pathname) : ReloadableXMLFile(pathname) {}
+        ~XMLTrust() {}
 
-        void lock();
-        void unlock() { m_lock->unlock(); }
         saml::Iterator<XSECCryptoX509*> getCertificates(const XMLCh* subject) const;
-        bool validate(const ISite* site, saml::Iterator<XSECCryptoX509*> certs) const;
-        bool validate(const ISite* site, saml::Iterator<const XMLCh*> certs) const;
+        bool validate(const ISite* site, const saml::Iterator<XSECCryptoX509*>& certs) const;
+        bool validate(const ISite* site, const saml::Iterator<const XMLCh*>& certs) const;
         bool attach(const ISite* site, SSL_CTX* ctx) const;
 
-    private:
-        std::string m_source;
-        time_t m_filestamp;
-        RWLock* m_lock;
-        XMLTrustImpl* m_impl;
+    protected:
+        virtual ReloadableXMLFileImpl* newImplementation(const char* pathname) const;
     };
 
 }
 
 extern "C" ITrust* XMLTrustFactory(const char* source)
 {
-    return new XMLTrust(source);
+    XMLTrust* t=new XMLTrust(source);
+    try
+    {
+        t->getImplementation();
+    }
+    catch (...)
+    {
+        delete t;
+        throw;
+    }
+    return t;    
+}
+
+
+ReloadableXMLFileImpl* XMLTrust::newImplementation(const char* pathname) const
+{
+    return new XMLTrustImpl(pathname);
 }
 
 X509_STORE* XMLTrustImpl::KeyAuthority::getX509Store(bool cached)
@@ -194,21 +203,13 @@ XMLTrustImpl::KeyAuthority::~KeyAuthority()
         delete (*j);
 }
 
-XMLTrustImpl::XMLTrustImpl(const char* pathname) : m_doc(NULL)
+XMLTrustImpl::XMLTrustImpl(const char* pathname) : ReloadableXMLFileImpl(pathname)
 {
     NDC ndc("XMLTrustImpl");
     Category& log=Category::getInstance(SHIB_LOGCAT".XMLTrustImpl");
 
-    saml::XML::Parser p;
     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);
-        m_doc=p.parse(dsrc);
-
-        log.infoStream() << "Loaded and parsed trust file (" << pathname << ")" << CategoryStream::ENDLINE;
-
         DOMElement* e = m_doc->getDocumentElement();
         if (XMLString::compareString(XML::SHIB_NS,e->getNamespaceURI()) ||
             XMLString::compareString(SHIB_L(Trust),e->getLocalName()))
@@ -268,7 +269,7 @@ XMLTrustImpl::XMLTrustImpl(const char* pathname) : m_doc(NULL)
     }
     catch (SAMLException& e)
     {
-        log.errorStream() << "XML error while parsing trust configuration: " << e.what() << CategoryStream::ENDLINE;
+        log.errorStream() << "Error while parsing trust configuration: " << e.what() << CategoryStream::ENDLINE;
         for (vector<KeyAuthority*>::iterator i=m_keyauths.begin(); i!=m_keyauths.end(); i++)
             delete (*i);
         if (m_doc)
@@ -290,78 +291,13 @@ XMLTrustImpl::~XMLTrustImpl()
 {
     for (vector<KeyAuthority*>::iterator i=m_keyauths.begin(); i!=m_keyauths.end(); i++)
         delete (*i);
-    if (m_doc)
-        m_doc->release();
-}
-
-XMLTrust::XMLTrust(const char* pathname) : m_filestamp(0), m_source(pathname), 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 XMLTrustImpl(pathname);
-    m_lock=RWLock::create();
-}
-
-void XMLTrust::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
-                {
-                    XMLTrustImpl* new_mapper=new XMLTrustImpl(m_source.c_str());
-                    delete m_impl;
-                    m_impl=new_mapper;
-                    m_filestamp=stat_buf.st_mtime;
-                    m_lock->unlock();
-                }
-                catch(SAMLException& e)
-                {
-                    m_lock->unlock();
-                    saml::NDC ndc("lock");
-                    Category::getInstance(SHIB_LOGCAT".XMLTrust").error("failed to reload trust metadata, sticking with what we have: %s", e.what());
-                }
-                catch(...)
-                {
-                    m_lock->unlock();
-                    saml::NDC ndc("lock");
-                    Category::getInstance(SHIB_LOGCAT".XMLTrust").error("caught an unknown exception, sticking with what we have");
-                }
-            }
-            else
-            {
-                m_lock->unlock();
-            }
-            m_lock->rdlock();
-        }
-    }
 }
 
 Iterator<XSECCryptoX509*> XMLTrust::getCertificates(const XMLCh* subject) const
 {
     // Find the first matching entity binding.
-    for (XMLTrustImpl::BindingMap::const_iterator i=m_impl->m_bindings.begin(); i!=m_impl->m_bindings.end(); i++)
+    XMLTrustImpl* impl=dynamic_cast<XMLTrustImpl*>(getImplementation());
+    for (XMLTrustImpl::BindingMap::const_iterator i=impl->m_bindings.begin(); i!=impl->m_bindings.end(); i++)
     {
         if (i->second->m_type!=XMLTrustImpl::KeyAuthority::entity)
             continue;
@@ -400,7 +336,8 @@ bool XMLTrust::attach(const ISite* site, SSL_CTX* ctx) const
     NDC ndc("attach");
 
     // Use the matching bindings.
-    for (XMLTrustImpl::BindingMap::const_iterator i=m_impl->m_bindings.begin(); i!=m_impl->m_bindings.end(); i++)
+    XMLTrustImpl* impl=dynamic_cast<XMLTrustImpl*>(getImplementation());
+    for (XMLTrustImpl::BindingMap::const_iterator i=impl->m_bindings.begin(); i!=impl->m_bindings.end(); i++)
     {
         if (i->second->m_type!=XMLTrustImpl::KeyAuthority::authority)
             continue;
@@ -461,7 +398,7 @@ bool XMLTrust::attach(const ISite* site, SSL_CTX* ctx) const
     return false;
 }
 
-bool XMLTrust::validate(const ISite* site, Iterator<XSECCryptoX509*> certs) const
+bool XMLTrust::validate(const ISite* site, const Iterator<XSECCryptoX509*>& certs) const
 {
     vector<const XMLCh*> temp;
     while (certs.hasNext())
@@ -469,14 +406,14 @@ bool XMLTrust::validate(const ISite* site, Iterator<XSECCryptoX509*> certs) cons
     return validate(site,temp);
 }
 
-bool XMLTrust::validate(const ISite* site, Iterator<const XMLCh*> certs) const
+bool XMLTrust::validate(const ISite* site, const Iterator<const XMLCh*>& certs) const
 {
     NDC ndc("validate");
 
     STACK_OF(X509)* chain=sk_X509_new_null();
     while (certs.hasNext())
     {
-        auto_ptr<char> temp(XMLString::transcode(certs.next()));
+        auto_ptr_char temp(certs.next());
         X509* x=B64_to_X509(temp.get());
         if (!x)
         {
@@ -487,7 +424,8 @@ bool XMLTrust::validate(const ISite* site, Iterator<const XMLCh*> certs) const
     }
 
     // Use the matching bindings.
-    for (XMLTrustImpl::BindingMap::const_iterator i=m_impl->m_bindings.begin(); i!=m_impl->m_bindings.end(); i++)
+    XMLTrustImpl* impl=dynamic_cast<XMLTrustImpl*>(getImplementation());
+    for (XMLTrustImpl::BindingMap::const_iterator i=impl->m_bindings.begin(); i!=impl->m_bindings.end(); i++)
     {
         if (i->second->m_type!=XMLTrustImpl::KeyAuthority::authority)
             continue;
@@ -514,7 +452,7 @@ bool XMLTrust::validate(const ISite* site, Iterator<const XMLCh*> certs) const
             }
             catch (XMLException& ex)
             {
-                auto_ptr<char> tmp(XMLString::transcode(ex.getMessage()));
+                auto_ptr_char tmp(ex.getMessage());
                 Category& log=Category::getInstance(SHIB_LOGCAT".XMLTrust");
                 log.errorStream() << "caught exception while parsing regular expression: " << tmp.get()
                     << CategoryStream::ENDLINE;
index 32b1b59..4a8fe67 100644 (file)
@@ -71,7 +71,6 @@
 #endif
 
 #include "shib.h"
-#include "shib-threads.h"
 
 #include <openssl/x509.h>
 
@@ -82,11 +81,17 @@ namespace shibboleth
     class ClubShibPOSTProfile : public ShibPOSTProfile
     {
     public:
-        ClubShibPOSTProfile(const saml::Iterator<const XMLCh*>& policies, const XMLCh* receiver, int ttlSeconds);
-        ClubShibPOSTProfile(const saml::Iterator<const XMLCh*>& policies, const XMLCh* issuer);
+        ClubShibPOSTProfile(
+            const saml::Iterator<IMetadata*>& metadatas, const saml::Iterator<ITrust*>& trusts,
+            const saml::Iterator<const XMLCh*>& policies, const XMLCh* receiver, int ttlSeconds
+            );
+        ClubShibPOSTProfile(
+            const saml::Iterator<IMetadata*>& metadatas, const saml::Iterator<ICredentials*>& creds,
+            const saml::Iterator<const XMLCh*>& policies, const XMLCh* issuer
+            );
         virtual ~ClubShibPOSTProfile();
 
-        virtual saml::SAMLResponse* prepare(
+        saml::SAMLResponse* prepare(
             const XMLCh* recipient,
             const XMLCh* name,
             const XMLCh* nameQualifier,
@@ -101,7 +106,7 @@ namespace shibboleth
             );
 
     protected:
-        virtual void verifySignature(
+        void verifySignature(
             const saml::SAMLSignedObject& obj,
             const IOriginSite* originSite,
             const XMLCh* signerName,
@@ -111,7 +116,13 @@ namespace shibboleth
     class ShibSOAPBinding : public saml::SAMLSOAPBinding
     {
     public:
-        ShibSOAPBinding(const XMLCh* subject, const ISite* relyingParty) : m_subject(subject), m_relyingParty(relyingParty) {}
+        ShibSOAPBinding(
+            const saml::Iterator<IMetadata*>& metadatas,
+            const saml::Iterator<ITrust*>& trusts,
+            const saml::Iterator<ICredentials*>& creds,
+            const XMLCh* subject,
+            const ISite* relyingParty
+            ) : m_metadatas(metadatas), m_creds(creds), m_trusts(trusts), m_subject(subject), m_relyingParty(relyingParty) {}
         virtual ~ShibSOAPBinding() {}
 
         virtual saml::SAMLResponse* send(
@@ -124,6 +135,9 @@ namespace shibboleth
         friend bool ssl_ctx_callback(void* ssl_ctx, void* userptr);
         const XMLCh* m_subject;
         const ISite* m_relyingParty;
+        const saml::Iterator<IMetadata*>& m_metadatas;
+        const saml::Iterator<ITrust*>& m_trusts;
+        const saml::Iterator<ICredentials*>& m_creds;
     };
 
     class ShibInternalConfig : public ShibConfig
@@ -132,24 +146,20 @@ namespace shibboleth
         ShibInternalConfig() {}
 
         bool init();
-        void term();
+        void term() {}
 
         void regFactory(const char* type, MetadataFactory* factory);
         void regFactory(const char* type, TrustFactory* factory);
         void regFactory(const char* type, CredentialsFactory* factory);
         void regFactory(const char* type, CredResolverFactory* factory);
         void regFactory(const char* type, AAPFactory* factory);
-        void regFactory(const char* type, saml::SAMLAttributeFactory* factory);
         void unregFactory(const char* type);
         
-        bool addMetadata(const char* type, const char* source);
-
-        saml::Iterator<IMetadata*> getMetadataProviders() const {return m_providers;}
-        saml::Iterator<ITrust*> getTrustProviders() const {return m_trust_providers;}
-        saml::Iterator<ICredentials*> getCredentialProviders() const {return m_cred_providers;}
-        CredResolverFactory* getCredResolverFactory(const char* type) const;
-        saml::Iterator<IAAP*> getAAPProviders() const {return m_aap_providers;}
-        saml::SAMLAttributeFactory* getAttributeFactory(const char* type) const;
+        IMetadata* newMetadata(const char* type, const char* source) const;
+        ITrust* newTrust(const char* type, const char* source) const;
+        ICredentials* newCredentials(const char* type, const char* source) const;
+        IAAP* newAAP(const char* type, const char* source) const;
+        ICredResolver* newCredResolver(const char* type, const DOMElement* source) const;
 
     private:
         friend class OriginMetadata;
@@ -162,17 +172,11 @@ namespace shibboleth
         typedef std::map<std::string, CredentialsFactory*> CredentialsFactoryMap;
         typedef std::map<std::string, CredResolverFactory*> CredResolverFactoryMap;
         typedef std::map<std::string, AAPFactory*> AAPFactoryMap;
-        typedef std::map<std::string, saml::SAMLAttributeFactory*> AttributeFactoryMap;
         MetadataFactoryMap m_metadataFactoryMap;
         TrustFactoryMap m_trustFactoryMap;
         CredentialsFactoryMap m_credFactoryMap;
         CredResolverFactoryMap m_credResolverFactoryMap;
         AAPFactoryMap m_aapFactoryMap;
-        AttributeFactoryMap m_attrFactoryMap;
-        std::vector<IMetadata*> m_providers;
-        std::vector<ITrust*> m_trust_providers;
-        std::vector<ICredentials*> m_cred_providers;
-        std::vector<IAAP*> m_aap_providers;
     };
 
     // OpenSSL Utilities
index 08242d1..03f2e22 100644 (file)
@@ -43,7 +43,7 @@ RSC=rc.exe
 # PROP Ignore_Export_Lib 0
 # PROP Target_Dir ""
 # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SHIB_EXPORTS" /YX /FD /c
-# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I "." /I "..\..\..\opensaml\c" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I ".." /I "." /I "..\..\..\opensaml\c" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
 # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
 # ADD BASE RSC /l 0x409 /d "NDEBUG"
@@ -69,7 +69,7 @@ LINK32=link.exe
 # PROP Ignore_Export_Lib 0
 # PROP Target_Dir ""
 # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SHIB_EXPORTS" /YX /FD /GZ /c
-# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /ZI /Od /I "." /I "..\..\..\opensaml\c" /D "_WINDOWS" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_AFXDLL" /FR /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /ZI /Od /I ".." /I "." /I "..\..\..\opensaml\c" /D "_WINDOWS" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_AFXDLL" /FR /YX /FD /GZ /c
 # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
 # ADD BASE RSC /l 0x409 /d "_DEBUG"
@@ -117,6 +117,10 @@ SOURCE=.\Metadata.cpp
 # End Source File
 # Begin Source File
 
+SOURCE=.\ReloadableXMLFile.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\SAMLBindingFactory.cpp
 # End Source File
 # Begin Source File
@@ -153,10 +157,6 @@ SOURCE=.\ShibSOAPBinding.cpp
 # End Source File
 # Begin Source File
 
-SOURCE=.\SimpleAttribute.cpp
-# End Source File
-# Begin Source File
-
 SOURCE=.\XML.cpp
 # End Source File
 # Begin Source File
index 0083591..6379a1d 100644 (file)
@@ -60,6 +60,7 @@
 #define __shib_h__
 
 #include <saml/saml.h>
+#include <shib/shib-threads.h>
 #include <openssl/ssl.h>
 
 #ifdef WIN32
@@ -95,6 +96,13 @@ namespace shibboleth
 
     // Metadata abstract interfaces
     
+    struct SHIB_EXPORTS ILockable
+    {
+        virtual void lock()=0;
+        virtual void unlock()=0;
+        virtual ~ILockable() {}
+    };
+    
     struct SHIB_EXPORTS IContactInfo
     {
         enum ContactType { technical, administrative, billing, other };
@@ -103,15 +111,17 @@ namespace shibboleth
         virtual const char* getEmail() const=0;
         virtual ~IContactInfo() {}
     };
-
+    
+    struct SHIB_EXPORTS ITrust; // forward decl
+    
     struct SHIB_EXPORTS ISite
     {
         virtual const XMLCh* getName() const=0;
         virtual saml::Iterator<const XMLCh*> getGroups() const=0;
         virtual saml::Iterator<const IContactInfo*> getContacts() const=0;
         virtual const char* getErrorURL() const=0;
-        virtual bool validate(saml::Iterator<XSECCryptoX509*> certs) const=0;
-        virtual bool validate(saml::Iterator<const XMLCh*> certs) const=0;
+        virtual bool validate(const saml::Iterator<ITrust*>& trusts, const saml::Iterator<XSECCryptoX509*>& certs) const=0;
+        virtual bool validate(const saml::Iterator<ITrust*>& trusts, const saml::Iterator<const XMLCh*>& certs) const=0;
         virtual ~ISite() {}
     };
     
@@ -130,29 +140,23 @@ namespace shibboleth
         virtual ~IOriginSite() {}
     };
 
-    struct SHIB_EXPORTS IMetadata
+    struct SHIB_EXPORTS IMetadata : public virtual ILockable
     {
-        virtual void lock()=0;
-        virtual void unlock()=0;
         virtual const ISite* lookup(const XMLCh* site) const=0;
         virtual ~IMetadata() {}
     };
 
-    struct SHIB_EXPORTS ITrust
+    struct SHIB_EXPORTS ITrust : public virtual ILockable
     {
-        virtual void lock()=0;
-        virtual void unlock()=0;
         virtual saml::Iterator<XSECCryptoX509*> getCertificates(const XMLCh* subject) const=0;
-        virtual bool validate(const ISite* site, saml::Iterator<XSECCryptoX509*> certs) const=0;
-        virtual bool validate(const ISite* site, saml::Iterator<const XMLCh*> certs) const=0;
+        virtual bool validate(const ISite* site, const saml::Iterator<XSECCryptoX509*>& certs) const=0;
+        virtual bool validate(const ISite* site, const saml::Iterator<const XMLCh*>& certs) const=0;
         virtual bool attach(const ISite* site, SSL_CTX* ctx) const=0;
         virtual ~ITrust() {}
     };
     
-    struct SHIB_EXPORTS ICredentials
+    struct SHIB_EXPORTS ICredentials : public virtual ILockable
     {
-        virtual void lock()=0;
-        virtual void unlock()=0;
         virtual bool attach(const XMLCh* subject, const ISite* relyingParty, SSL_CTX* ctx) const=0;
         virtual ~ICredentials() {}
     };
@@ -173,14 +177,12 @@ namespace shibboleth
         virtual const char* getFactory() const=0;
         virtual const char* getAlias() const=0;
         virtual const char* getHeader() const=0;
-        virtual bool accept(const XMLCh* originSite, const DOMElement* e) const=0;
+        virtual void apply(const IOriginSite* originSite, saml::SAMLAttribute& attribute) const=0;
         virtual ~IAttributeRule() {}
     };
     
-    struct SHIB_EXPORTS IAAP
+    struct SHIB_EXPORTS IAAP : public virtual ILockable
     {
-        virtual void lock()=0;
-        virtual void unlock()=0;
         virtual const IAttributeRule* lookup(const XMLCh* attrName, const XMLCh* attrNamespace=NULL) const=0;
         virtual const IAttributeRule* lookup(const char* alias) const=0;
         virtual saml::Iterator<const IAttributeRule*> getAttributeRules() const=0;
@@ -204,22 +206,7 @@ namespace shibboleth
     template class SHIB_EXPORTS saml::ArrayIterator<IAAP*>;
 #endif
 
-    class SHIB_EXPORTS SimpleAttribute : public saml::SAMLAttribute
-    {
-    public:
-        SimpleAttribute(const XMLCh* name, const XMLCh* ns, long lifetime=0,
-                        const saml::Iterator<const XMLCh*>& values=EMPTY(const XMLCh*));
-        SimpleAttribute(DOMElement* e);
-        virtual saml::SAMLObject* clone() const;
-        virtual ~SimpleAttribute();
-
-    protected:
-        virtual bool accept(DOMElement* e) const;
-
-        const XMLCh* m_originSite;
-    };
-
-    class SHIB_EXPORTS ScopedAttribute : public SimpleAttribute
+    class SHIB_EXPORTS ScopedAttribute : public saml::SAMLAttribute
     {
     public:
         ScopedAttribute(const XMLCh* name, const XMLCh* ns, long lifetime=0,
@@ -228,15 +215,18 @@ namespace shibboleth
         ScopedAttribute(DOMElement* e);
         virtual ~ScopedAttribute();
 
-        virtual DOMNode* toDOM(DOMDocument* doc=NULL, bool xmlns=true) const;
         virtual saml::SAMLObject* clone() const;
 
         virtual saml::Iterator<const XMLCh*> getValues() const;
         virtual saml::Iterator<std::string> getSingleByteValues() const;
+        virtual void setValues(const saml::Iterator<const XMLCh*>& values=EMPTY(const XMLCh*));
+        virtual void addValue(const XMLCh* value);
+        virtual void removeValue(unsigned int index);
 
     protected:
-        virtual bool addValue(DOMElement* e);
+        virtual void valueToDOM(unsigned int index, DOMElement* e) const;
 
+        const XMLCh* m_originSite;
         std::vector<const XMLCh*> m_scopes;
         mutable std::vector<const XMLCh*> m_scopedValues;
     };
@@ -244,9 +234,15 @@ namespace shibboleth
     class SHIB_EXPORTS ShibPOSTProfile
     {
     public:
-        ShibPOSTProfile(const saml::Iterator<const XMLCh*>& policies, const XMLCh* receiver, int ttlSeconds);
-        ShibPOSTProfile(const saml::Iterator<const XMLCh*>& policies, const XMLCh* issuer);
-        virtual ~ShibPOSTProfile();
+        ShibPOSTProfile(
+            const saml::Iterator<IMetadata*>& metadatas, const saml::Iterator<ITrust*>& trusts,
+            const saml::Iterator<const XMLCh*>& policies, const XMLCh* receiver, int ttlSeconds
+            );
+        ShibPOSTProfile(
+            const saml::Iterator<IMetadata*>& metadatas, const saml::Iterator<ICredentials*>& creds,
+            const saml::Iterator<const XMLCh*>& policies, const XMLCh* issuer
+            );
+        virtual ~ShibPOSTProfile() {}
 
         virtual const saml::SAMLAssertion* getSSOAssertion(const saml::SAMLResponse& r);
         virtual const saml::SAMLAuthenticationStatement* getSSOStatement(const saml::SAMLAssertion& a);
@@ -276,21 +272,26 @@ namespace shibboleth
             XSECCryptoKey* knownKey=NULL);
 
         signatureMethod m_algorithm;
-        std::vector<const XMLCh*> m_policies;
-        XMLCh* m_issuer;
-        XMLCh* m_receiver;
+        const saml::Iterator<const XMLCh*>& m_policies;
+        const saml::Iterator<IMetadata*>& m_metadatas;
+        const saml::Iterator<ITrust*>& m_trusts;
+        const saml::Iterator<ICredentials*>& m_creds;
+        const XMLCh* m_issuer;
+        const XMLCh* m_receiver;
         int m_ttlSeconds;
-
-    private:
-        ShibPOSTProfile(const ShibPOSTProfile&) {}
-        ShibPOSTProfile& operator=(const ShibPOSTProfile&) {return *this;}
     };
 
     class SHIB_EXPORTS ShibPOSTProfileFactory
     {
     public:
-        static ShibPOSTProfile* getInstance(const saml::Iterator<const XMLCh*>& policies, const XMLCh* receiver, int ttlSeconds);
-        static ShibPOSTProfile* getInstance(const saml::Iterator<const XMLCh*>& policies, const XMLCh* issuer);
+        static ShibPOSTProfile* getInstance(
+            const saml::Iterator<IMetadata*>& metadatas, const saml::Iterator<ITrust*>& trusts,
+            const saml::Iterator<const XMLCh*>& policies, const XMLCh* receiver, int ttlSeconds
+            );
+        static ShibPOSTProfile* getInstance(
+            const saml::Iterator<IMetadata*>& metadatas, const saml::Iterator<ICredentials*>& creds,
+            const saml::Iterator<const XMLCh*>& policies, const XMLCh* issuer
+            );
     };
 
     // Glue classes between abstract metadata and concrete providers
@@ -298,7 +299,7 @@ namespace shibboleth
     class SHIB_EXPORTS OriginMetadata
     {
     public:
-        OriginMetadata(const XMLCh* site);
+        OriginMetadata(const saml::Iterator<IMetadata*>& metadatas, const XMLCh* site);
         ~OriginMetadata();
         bool fail() const {return m_mapper==NULL;}
         const IOriginSite* operator->() const {return m_site;}
@@ -314,7 +315,7 @@ namespace shibboleth
     class SHIB_EXPORTS Trust
     {
     public:
-        Trust() : m_mapper(NULL) {}
+        Trust(const saml::Iterator<ITrust*>& trusts) : m_trusts(trusts), m_mapper(NULL) {}
         ~Trust();
         saml::Iterator<XSECCryptoX509*> getCertificates(const XMLCh* subject);
         bool validate(const ISite* site, saml::Iterator<XSECCryptoX509*> certs) const;
@@ -325,24 +326,29 @@ namespace shibboleth
         Trust(const Trust&);
         void operator=(const Trust&);
         ITrust* m_mapper;
+        const saml::Iterator<ITrust*>& m_trusts;
     };
     
     class SHIB_EXPORTS Credentials
     {
     public:
-        static bool attach(const XMLCh* subject, const ISite* relyingParty, SSL_CTX* ctx);
+        static bool attach(
+            const saml::Iterator<ICredentials*>& creds, const XMLCh* subject, const ISite* relyingParty, SSL_CTX* ctx
+            );
     };
 
     class SHIB_EXPORTS AAP
     {
     public:
-        AAP(const XMLCh* attrName, const XMLCh* attrNamespace=NULL);
-        AAP(const char* alias);
+        AAP(const saml::Iterator<IAAP*>& aaps, const XMLCh* attrName, const XMLCh* attrNamespace=NULL);
+        AAP(const saml::Iterator<IAAP*>& aaps, const char* alias);
         ~AAP();
         bool fail() const {return m_mapper==NULL;}
         const IAttributeRule* operator->() const {return m_rule;}
         operator const IAttributeRule*() const {return m_rule;}
         
+        static void apply(const saml::Iterator<IAAP*>& aaps, const IOriginSite* originSite, saml::SAMLAssertion& assertion);
+        
     private:
         AAP(const AAP&);
         void operator=(const AAP&);
@@ -354,7 +360,7 @@ namespace shibboleth
         typedef IMetadata* MetadataFactory(const char* source);
         typedef ITrust* TrustFactory(const char* source);
         typedef ICredentials* CredentialsFactory(const char* source);
-        typedef ICredResolver* CredResolverFactory(const DOMElement* e);
+        typedef ICredResolver* CredResolverFactory(const DOMElement* source);
         typedef IAAP* AAPFactory(const char* source);
     }
     
@@ -371,24 +377,20 @@ namespace shibboleth
         // enables runtime and clients to access configuration
         static ShibConfig& getConfig();
 
-        // allows pluggable implementations of metadata
+        // allows pluggable implementations of metadata and configuration data
         virtual void regFactory(const char* type, MetadataFactory* factory)=0;
         virtual void regFactory(const char* type, TrustFactory* factory)=0;
         virtual void regFactory(const char* type, CredentialsFactory* factory)=0;
         virtual void regFactory(const char* type, CredResolverFactory* factory)=0;
         virtual void regFactory(const char* type, AAPFactory* factory)=0;
-        virtual void regFactory(const char* type, saml::SAMLAttributeFactory* factory)=0;
         virtual void unregFactory(const char* type)=0;
         
-        // builds a specific metadata lookup object
-        virtual bool addMetadata(const char* type, const char* source)=0;
-        
-        virtual saml::Iterator<IMetadata*> getMetadataProviders() const=0;
-        virtual saml::Iterator<ITrust*> getTrustProviders() const=0;
-        virtual saml::Iterator<ICredentials*> getCredentialProviders() const=0;
-        virtual CredResolverFactory* getCredResolverFactory(const char* type) const=0;
-        virtual saml::Iterator<IAAP*> getAAPProviders() const=0;
-        virtual saml::SAMLAttributeFactory* getAttributeFactory(const char* type) const=0;
+        // build a specific metadata lookup object
+        virtual IMetadata* newMetadata(const char* type, const char* source) const=0;
+        virtual ITrust* newTrust(const char* type, const char* source) const=0;
+        virtual ICredentials* newCredentials(const char* type, const char* source) const=0;
+        virtual IAAP* newAAP(const char* type, const char* source) const=0;
+        virtual ICredResolver* newCredResolver(const char* type, const DOMElement* source) const=0;
     };
 
     struct SHIB_EXPORTS Constants
@@ -398,7 +400,7 @@ namespace shibboleth
         
         static const XMLCh XMLSIG_RETMETHOD_RAWX509[];  // DER X.509 defined by xmlsig
         
-        static saml::QName SHIB_ATTRIBUTE_VALUE_TYPE; 
+        static saml::QName SHIB_ATTRIBUTE_VALUE_TYPE;
     };
 
     class SHIB_EXPORTS XML
@@ -478,10 +480,50 @@ namespace shibboleth
     {
     public:
         static saml::SAMLBinding* getInstance(
+            const saml::Iterator<IMetadata*>& metadatas,
+            const saml::Iterator<ITrust*>& trusts,
+            const saml::Iterator<ICredentials*>& creds,
             const XMLCh* subject,
             const ISite* relyingParty,
             const XMLCh* protocol=saml::SAMLBinding::SAML_SOAP_HTTPS);
     };
+
+    /* Helper classes for implementing reloadable XML-based config files
+       The ILockable interface will usually be inherited twice, once as
+       part of the external interface to clients and once as an implementation
+       detail of the reloading class below.
+     */
+    
+    class SHIB_EXPORTS ReloadableXMLFileImpl
+    {
+    public:
+        ReloadableXMLFileImpl(const char* pathname);
+        virtual ~ReloadableXMLFileImpl();
+        
+    protected:
+        DOMDocument* m_doc;
+    };
+
+    class SHIB_EXPORTS ReloadableXMLFile : protected virtual ILockable
+    {
+    public:
+        ReloadableXMLFile(const char* pathname);
+        ~ReloadableXMLFile() { delete m_lock; delete m_impl; }
+
+        virtual void lock();
+        virtual void unlock() { m_lock->unlock(); }
+
+        ReloadableXMLFileImpl* getImplementation() const;
+
+    protected:
+        virtual ReloadableXMLFileImpl* newImplementation(const char* pathname) const=0;
+        
+    private:
+        std::string m_source;
+        time_t m_filestamp;
+        RWLock* m_lock;
+        mutable ReloadableXMLFileImpl* m_impl;
+    };
 }
 
 #endif