# 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
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
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
# 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 =
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)
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();
}
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;
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. "
// 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.
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;
// 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");
// 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);
}
// 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())
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);
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()));
+ }
}
}
}
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)
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());
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);
// 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()) {
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;
// 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"},
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)
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;
}
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.
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,
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;
}
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++)
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())
}
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());
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);
+ }
+ }
}
}
}
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());
}
}
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());
+ }
+ }
}
}
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)
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;
// 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;
}
}
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;
}
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;
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;
// 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());
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);
}
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;
}
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);
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
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");
// 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);
<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
<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
<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
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()
shib-config.cpp \
shib-ini.cpp \
shib-mlp.cpp \
- shib-resource.cpp \
shib-resourceentry.cpp \
shib-rm.cpp \
shib-rpcerror.cpp \
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
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);
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
{
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;
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()
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)
{
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
}
{
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(
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(
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;
}
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;
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?
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
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(); }
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);
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;
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);
return (CCache*) new InternalCCache();
}
-// static members
-vector<SAMLAssertion*> InternalCCacheEntry::g_emptyVector;
-
/******************************************************************************/
/* InternalCCache: A Credential Cache */
InternalCCache::InternalCCache()
{
- string ctx="shibtarget.InternalCCache";
- log = &(log4cpp::Category::getInstance(ctx));
+ log = &(log4cpp::Category::getInstance("shibtarget.InternalCCache"));
lock = RWLock::create();
shutdown_wait = CondWait::create();
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);
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();
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();
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()
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))
// entry is invalid (expired) -- go fetch a new one.
log->debug("removing resource cache; assertion is invalid");
- remove (resource.getResource());
+ remove(resource);
delete entry;
}
}
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;
// 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();
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);
#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;
CCache* shibtarget::g_shibTargetCCache = NULL;
+
/****************************************************************************/
// External Interface
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));
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)) {
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();
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;
#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();
+}
+++ /dev/null
-/*
- * 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);
-}
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
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();
// 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;
#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();
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);
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)
{
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));
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;
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);
}
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();
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())
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())
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);
}
-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");
}
// 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);
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;
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");
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;
#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"
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
{
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;
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;
};
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:
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
// 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());
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;
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);
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;
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) {
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);
}
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;
{
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))
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;
}
#include <rpc/rpc.h>
-#ifndef WIN32
#include <pthread.h>
-#endif
#ifdef __cplusplus
extern "C" {
struct shibrpc_session_is_valid_args_1 {
ShibRpcHttpCookie_1 cookie;
- char *url;
+ char *application_id;
bool_t checkIPAddress;
long lifetime;
long timeout;
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;
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;
struct shibrpc_session_is_valid_args_1 {
ShibRpcHttpCookie_1 cookie;
- string url<>;
+ string application_id<>;
bool checkIPAddress;
long lifetime;
long timeout;
};
struct shibrpc_new_session_args_1 {
+ string application_id<>;
string shire_location<>;
string saml_post<>;
string client_addr<>;
struct shibrpc_get_assertions_args_1 {
ShibRpcHttpCookie_1 cookie;
bool checkIPAddress;
- string url<>;
+ string application_id<>;
};
struct shibrpc_get_assertions_ret_1 {
# 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
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
namespace shibboleth {
- class XMLAAPImpl
+ class XMLAAPImpl : public ReloadableXMLFileImpl
{
public:
XMLAAPImpl(const char* pathname);
~XMLAAPImpl();
- void regAttributes() const;
-
class AttributeRule : public IAttributeRule
{
public:
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
{
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()))
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
}
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)
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};
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
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 {
}
}
-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));
{
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;
}
#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);
{
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;
}
// 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();
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());
}
}
#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);
{
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;
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();
+}
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() {}
Constants.cpp \
CredResolvers.cpp \
Metadata.cpp \
+ ReloadableXMLFile.cpp \
SAMLBindingFactory.cpp \
ShibConfig.cpp \
ShibPOSTProfile.cpp \
*/
#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)))
{
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())
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();
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();
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();
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();
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))
{
}
}
-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))
{
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();
+}
--- /dev/null
+/*
+ * 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;
+}
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);
}
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");
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()
{
}
}
-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};
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);
+}
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);
}
// 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);
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)
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)
}
}
-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()
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)
// 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())
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);
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;
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)");
}
}
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);
}
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");
+++ /dev/null
-/*
- * 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);
-}
namespace shibboleth {
- class XMLCredentialsImpl
+ class XMLCredentialsImpl : public ReloadableXMLFileImpl
{
public:
XMLCredentialsImpl(const char* pathname);
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)
}
}
-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()))
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)
}
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++)
m_doc->release();
throw;
}
+#ifndef _DEBUG
catch (...)
{
log.error("Unexpected error while parsing creds configuration");
m_doc->release();
throw;
}
+#endif
}
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;
namespace shibboleth {
- class XMLMetadataImpl
+ class XMLMetadataImpl : public ReloadableXMLFileImpl
{
public:
XMLMetadataImpl(const char* pathname);
{
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;}
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;
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()
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()))
}
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)
{
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;
}
namespace shibboleth {
- class XMLTrustImpl
+ class XMLTrustImpl : public ReloadableXMLFileImpl
{
public:
XMLTrustImpl(const char* pathname);
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)
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()))
}
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)
{
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;
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;
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())
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)
{
}
// 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;
}
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;
#endif
#include "shib.h"
-#include "shib-threads.h"
#include <openssl/x509.h>
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,
);
protected:
- virtual void verifySignature(
+ void verifySignature(
const saml::SAMLSignedObject& obj,
const IOriginSite* originSite,
const XMLCh* signerName,
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(
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
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;
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
# 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"
# 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"
# End Source File
# Begin Source File
+SOURCE=.\ReloadableXMLFile.cpp
+# End Source File
+# Begin Source File
+
SOURCE=.\SAMLBindingFactory.cpp
# End Source File
# Begin Source File
# End Source File
# Begin Source File
-SOURCE=.\SimpleAttribute.cpp
-# End Source File
-# Begin Source File
-
SOURCE=.\XML.cpp
# End Source File
# Begin Source File
#define __shib_h__
#include <saml/saml.h>
+#include <shib/shib-threads.h>
#include <openssl/ssl.h>
#ifdef WIN32
// 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 };
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() {}
};
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() {}
};
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;
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,
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;
};
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);
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
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;}
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;
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&);
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);
}
// 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
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
{
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