// globals
namespace {
+ static const XMLCh name[] = { chLatin_n, chLatin_a, chLatin_m, chLatin_e, chNull };
+ static const XMLCh port[] = { chLatin_p, chLatin_o, chLatin_r, chLatin_t, chNull };
+ static const XMLCh scheme[] = { chLatin_s, chLatin_c, chLatin_h, chLatin_e, chLatin_m, chLatin_e, chNull };
+ static const XMLCh id[] = { chLatin_i, chLatin_d, chNull };
+ static const XMLCh Implementation[] =
+ { chLatin_I, chLatin_m, chLatin_p, chLatin_l, chLatin_e, chLatin_m, chLatin_e, chLatin_n, chLatin_t, chLatin_a, chLatin_t, chLatin_i, chLatin_o, chLatin_n, chNull };
+ static const XMLCh ISAPI[] = { chLatin_I, chLatin_S, chLatin_A, chLatin_P, chLatin_I, chNull };
+ static const XMLCh normalizeRequest[] =
+ { chLatin_n, chLatin_o, chLatin_r, chLatin_m, chLatin_a, chLatin_l, chLatin_i, chLatin_z, chLatin_e,
+ chLatin_R, chLatin_e, chLatin_q, chLatin_u, chLatin_e, chLatin_s, chLatin_t, chNull
+ };
+ static const XMLCh Site[] = { chLatin_S, chLatin_i, chLatin_t, chLatin_e, chNull };
+
+ struct site_t {
+ site_t(const DOMElement* e)
+ {
+ auto_ptr_char n(e->getAttributeNS(NULL,name));
+ auto_ptr_char s(e->getAttributeNS(NULL,scheme));
+ auto_ptr_char p(e->getAttributeNS(NULL,port));
+ if (n.get()) m_name=n.get();
+ if (s.get()) m_scheme=s.get();
+ if (p.get()) m_port=p.get();
+ }
+ string m_scheme,m_name,m_port;
+ };
+
HINSTANCE g_hinstDLL;
ShibTargetConfig* g_Config = NULL;
- map<string,string> g_Sites;
+ map<string,site_t> g_Sites;
bool g_bNormalizeRequest = true;
}
return TRUE; // cleanup should happen when filter unloads
}
-static const XMLCh host[] = { chLatin_h, chLatin_o, chLatin_s, chLatin_t, chNull };
-static const XMLCh id[] = { chLatin_i, chLatin_d, chNull };
-static const XMLCh Implementation[] =
-{ chLatin_I, chLatin_m, chLatin_p, chLatin_l, chLatin_e, chLatin_m, chLatin_e, chLatin_n, chLatin_t, chLatin_a, chLatin_t, chLatin_i, chLatin_o, chLatin_n, chNull };
-static const XMLCh ISAPI[] = { chLatin_I, chLatin_S, chLatin_A, chLatin_P, chLatin_I, chNull };
-static const XMLCh normalizeRequest[] =
-{ chLatin_n, chLatin_o, chLatin_r, chLatin_m, chLatin_a, chLatin_l, chLatin_i, chLatin_z, chLatin_e,
- chLatin_R, chLatin_e, chLatin_q, chLatin_u, chLatin_e, chLatin_s, chLatin_t, chNull
-};
-static const XMLCh Site[] = { chLatin_S, chLatin_i, chLatin_t, chLatin_e, chNull };
-
extern "C" BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer)
{
if (!pVer)
ShibTargetConfig::Metadata |
ShibTargetConfig::AAP |
ShibTargetConfig::RequestMapper |
- ShibTargetConfig::SHIREExtensions
+ ShibTargetConfig::SHIREExtensions |
+ ShibTargetConfig::Logging
);
if (!g_Config->init(schemadir,config)) {
g_Config=NULL;
impl=saml::XML::getFirstChildElement(impl,ShibTargetConfig::SHIBTARGET_NS,Site);
while (impl) {
auto_ptr_char id(impl->getAttributeNS(NULL,id));
- auto_ptr_char host(impl->getAttributeNS(NULL,host));
- if (id.get() && host.get())
- g_Sites[id.get()]=host.get();
+ if (id.get())
+ g_Sites.insert(pair<string,site_t>(id.get(),site_t(impl)));
impl=saml::XML::getNextSiblingElement(impl,ShibTargetConfig::SHIBTARGET_NS,Site);
}
}
}
IRequestMapper::Settings map_request(
- PHTTP_FILTER_CONTEXT pfc, PHTTP_FILTER_PREPROC_HEADERS pn, IRequestMapper* mapper, const char* hostname, string& target
+ PHTTP_FILTER_CONTEXT pfc, PHTTP_FILTER_PREPROC_HEADERS pn, IRequestMapper* mapper, const site_t& site, string& target
)
{
- dynabuf port(10);
+ // URL path always come from IIS.
dynabuf url(256);
- GetServerVariable(pfc,"SERVER_PORT",port,10);
GetHeader(pn,pfc,"url",url,256,false);
+
+ // Port may come from IIS or from site def.
+ dynabuf port(11);
+ if (site.m_port.empty() || !g_bNormalizeRequest)
+ GetServerVariable(pfc,"SERVER_PORT",port,10);
+ else {
+ strncpy(port,site.m_port.c_str(),10);
+ static_cast<char*>(port)[10]=0;
+ }
+ // Scheme may come from site def or be derived from IIS.
+ const char* scheme=site.m_scheme.c_str();
+ if (!scheme || !*scheme || !g_bNormalizeRequest)
+ scheme=pfc->fIsSecurePort ? "https" : "http";
+
+ // Start with path.
if (!url.empty())
target=static_cast<char*>(url);
- if (port!=(pfc->fIsSecurePort ? "443" : "80"))
+
+ // If port is non-default, prepend it.
+ if ((!strcmp(scheme,"http") && port!="80") || (!strcmp(scheme,"https") && port!="443"))
target = ':' + static_cast<char*>(port) + target;
if (g_bNormalizeRequest) {
- target = string(pfc->fIsSecurePort ? "https://" : "http://") + hostname + target;
+ target = string(scheme) + "://" + site.m_name + target;
}
else {
dynabuf name(64);
GetServerVariable(pfc,"SERVER_NAME",name,64);
- target = string(pfc->fIsSecurePort ? "https://" : "http://") + static_cast<char*>(name) + target;
+ target = string(scheme) + "://" + static_cast<char*>(name) + target;
}
- return mapper->getSettingsFromParsedURL((pfc->fIsSecurePort ? "https" : "http"),hostname,strtoul(port,NULL,10),url);
+ return mapper->getSettingsFromParsedURL(scheme,site.m_name.c_str(),strtoul(port,NULL,10),url);
}
DWORD WriteClientError(PHTTP_FILTER_CONTEXT pfc, const char* msg)
if (p.first) {
ifstream infile(p.second);
if (!infile.fail()) {
- const char* res = mlp.run(infile);
+ const char* res = mlp.run(infile,props);
if (res) {
static const char* ctype="Content-Type: text/html\r\n";
pfc->AddResponseHeaders(pfc,const_cast<char*>(ctype),0);
GetServerVariable(pfc,"INSTANCE_ID",buf,10);
// Match site instance to host name, skip if no match.
- map<string,string>::const_iterator map_i=g_Sites.find(static_cast<char*>(buf));
+ map<string,site_t>::const_iterator map_i=g_Sites.find(static_cast<char*>(buf));
if (map_i==g_Sites.end())
return SF_STATUS_REQ_NEXT_NOTIFICATION;
- const string& site=map_i->second;
-
ostringstream threadid;
threadid << "[" << getpid() << "] isapi_shib" << '\0';
saml::NDC ndc(threadid.str().c_str());
string targeturl;
IRequestMapper* mapper=conf->getRequestMapper();
Locker locker2(mapper);
- IRequestMapper::Settings settings=map_request(pfc,pn,mapper,site.c_str(),targeturl);
+ IRequestMapper::Settings settings=map_request(pfc,pn,mapper,map_i->second,targeturl);
pair<bool,const char*> application_id=settings.first->getString("applicationId");
const IApplication* application=conf->getApplication(application_id.second);
- const IPropertySet* sessionProps=application ? application->getPropertySet("Sessions") : NULL;
- if (!application || !sessionProps)
- return WriteClientError(pfc,"Unable to map request to application session settings, check configuration.");
+ if (!application)
+ return WriteClientError(pfc,"Unable to map request to application settings, check configuration.");
// Declare SHIRE object for this request.
SHIRE shire(application);
// Now check the policy for this request.
pair<bool,bool> requireSession=settings.first->getBool("requireSession");
- pair<bool,const char*> shib_cookie=sessionProps->getString("cookieName");
- if (!shib_cookie.first)
- return WriteClientError(pfc,"No session cookie name defined for this application, check configuration.");
+ pair<const char*,const char*> shib_cookie=shire.getCookieNameProps();
// Check for session cookie.
const char* session_id=NULL;
GetHeader(pn,pfc,"Cookie:",buf,128,false);
Category::getInstance("isapi_shib.HttpFilterProc").debug("cookie header is {%s}",(const char*)buf);
- if (!buf.empty() && (session_id=strstr(buf,shib_cookie.second))) {
- session_id+=strlen(shib_cookie.second) + 1; /* Skip over the '=' */
+ if (!buf.empty() && (session_id=strstr(buf,shib_cookie.first))) {
+ session_id+=strlen(shib_cookie.first) + 1; /* Skip over the '=' */
char* cookieend=strchr(session_id,';');
if (cookieend)
*cookieend = '\0'; /* Ignore anyting after a ; */
// Make sure this session is still valid.
RPCError* status = NULL;
- ShibMLP markupProcessor(application);
+ ShibMLP markupProcessor;
markupProcessor.insert("requestURL", targeturl);
dynabuf abuf(16);
// Do we have an access control plugin?
if (settings.second) {
Locker acllock(settings.second);
- if (!settings.second->authorized(assertions)) {
+ if (!settings.second->authorized(*sso_statement,assertions)) {
for (int k = 0; k < assertions.size(); k++)
delete assertions[k];
delete sso_statement;
Iterator<const IAttributeRule*> rules=aap->getAttributeRules();
while (rules.hasNext()) {
const char* header=rules.next()->getHeader();
- if (header)
- pn->SetHeader(pfc,const_cast<char*>(header),"");
+ if (header) {
+ string hname=string(header) + ':';
+ pn->SetHeader(pfc,const_cast<char*>(hname.c_str()),"");
+ }
}
}
catch(...) {
pn->SetHeader(pfc,"Shib-Origin-Site:","");
pn->SetHeader(pfc,"Shib-Authentication-Method:","");
+ pn->SetHeader(pfc,"Shib-NameIdentifier-Format:","");
// Export the SAML AuthnMethod and the origin site name.
- if (sso_statement) {
- auto_ptr_char os(sso_statement->getSubject()->getNameIdentifier()->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()));
+ auto_ptr_char os(sso_statement->getSubject()->getNameIdentifier()->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 NameID?
+ AAP wrapper(provs,sso_statement->getSubject()->getNameIdentifier()->getFormat(),Constants::SHIB_ATTRIBUTE_NAMESPACE_URI);
+ if (!wrapper.fail() && wrapper->getHeader()) {
+ auto_ptr_char form(sso_statement->getSubject()->getNameIdentifier()->getFormat());
+ auto_ptr_char nameid(sso_statement->getSubject()->getNameIdentifier()->getName());
+ pn->SetHeader(pfc,"Shib-NameIdentifier-Format:",const_cast<char*>(form.get()));
+ if (!strcmp(wrapper->getHeader(),"REMOTE_USER")) {
+ char* principal=const_cast<char*>(nameid.get());
+ 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 hname=string(wrapper->getHeader()) + ':';
+ pn->SetHeader(pfc,const_cast<char*>(wrapper->getHeader()),const_cast<char*>(nameid.get()));
+ }
}
pn->SetHeader(pfc,"Shib-Application-ID:","");
SAMLAttribute* attr=attrs.next();
// Are we supposed to export it?
- AAP wrapper(application->getAAPProviders(),attr->getName(),attr->getNamespace());
- if (wrapper.fail())
+ AAP wrapper(provs,attr->getName(),attr->getNamespace());
+ if (wrapper.fail() || !wrapper->getHeader())
continue;
Iterator<string> vals=attr->getSingleByteValues();
}
IRequestMapper::Settings map_request(
- LPEXTENSION_CONTROL_BLOCK lpECB, IRequestMapper* mapper, const char* hostname, string& target
+ LPEXTENSION_CONTROL_BLOCK lpECB, IRequestMapper* mapper, const site_t& site, string& target
)
{
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");
+
+ // URL path always come from IIS.
+ dynabuf url(256);
+ GetServerVariable(lpECB,"URL",url,255);
+
+ // Port may come from IIS or from site def.
+ dynabuf port(11);
+ if (site.m_port.empty() || !g_bNormalizeRequest)
+ GetServerVariable(lpECB,"SERVER_PORT",port,10);
+ else {
+ strncpy(port,site.m_port.c_str(),10);
+ static_cast<char*>(port)[10]=0;
+ }
+
+ // Scheme may come from site def or be derived from IIS.
+ const char* scheme=site.m_scheme.c_str();
+ if (!scheme || !*scheme || !g_bNormalizeRequest)
+ scheme=lpECB->lpszMethod;
+ // Start with path.
if (!url.empty())
target=static_cast<char*>(url);
- if (port!=(SSL ? "443" : "80"))
+
+ // If port is non-default, prepend it.
+ if ((!strcmp(scheme,"http") && port!="80") || (!strcmp(scheme,"https") && port!="443"))
target = ':' + static_cast<char*>(port) + target;
if (g_bNormalizeRequest) {
- target = string(SSL ? "https://" : "http://") + hostname + target;
- return mapper->getSettingsFromParsedURL(lpECB->lpszMethod,hostname,strtoul(port,NULL,10),url);
+ target = string(scheme) + "://" + site.m_name + target;
}
else {
dynabuf name(64);
GetServerVariable(lpECB,"SERVER_NAME",name,64);
- target = string(SSL ? "https://" : "http://") + static_cast<char*>(name) + target;
- return mapper->getSettingsFromParsedURL((SSL ? "https" : "http"),name,strtoul(port,NULL,10),url);
+ target = string(scheme) + "://" + static_cast<char*>(name) + target;
}
+ return mapper->getSettingsFromParsedURL(scheme,site.m_name.c_str(),strtoul(port,NULL,10),url);
}
DWORD WriteClientError(LPEXTENSION_CONTROL_BLOCK lpECB, const char* msg)
if (p.first) {
ifstream infile(p.second);
if (!infile.fail()) {
- const char* res = mlp.run(infile);
+ const char* res = mlp.run(infile,props);
if (res) {
static const char* ctype="Content-Type: text/html\r\n";
lpECB->ServerSupportFunction(lpECB->ConnID,HSE_REQ_SEND_RESPONSE_HEADER,"200 OK",0,(LPDWORD)ctype);
GetServerVariable(lpECB,"INSTANCE_ID",buf,10);
// Match site instance to host name, skip if no match.
- map<string,string>::const_iterator map_i=g_Sites.find(static_cast<char*>(buf));
+ map<string,site_t>::const_iterator map_i=g_Sites.find(static_cast<char*>(buf));
if (map_i==g_Sites.end())
return WriteClientError(lpECB,"Shibboleth filter not configured for this web site.");
- const string& site=map_i->second;
-
// We lock the configuration system for the duration.
IConfig* conf=g_Config->getINI();
Locker locker(conf);
string targeturl;
IRequestMapper* mapper=conf->getRequestMapper();
Locker locker2(mapper);
- IRequestMapper::Settings settings=map_request(lpECB,mapper,site.c_str(),targeturl);
+ IRequestMapper::Settings settings=map_request(lpECB,mapper,map_i->second,targeturl);
pair<bool,const char*> application_id=settings.first->getString("applicationId");
application=conf->getApplication(application_id.second);
const IPropertySet* sessionProps=application ? application->getPropertySet("Sessions") : NULL;
if (!strstr(targeturl.c_str(),shire.getShireURL(targeturl.c_str())))
return WriteClientError(lpECB,"The request's application and associated shireURL setting are inconsistent.");;
- pair<bool,const char*> shib_cookie=sessionProps->getString("cookieName");
- pair<bool,const char*> shib_cookie_props=sessionProps->getString("cookieProps");
- if (!shib_cookie.first)
- return WriteClientError(lpECB,"No session cookie name defined for this application, check configuration.");
+ pair<const char*,const char*> shib_cookie=shire.getCookieNameProps();
// Make sure this is SSL, if it should be
pair<bool,bool> shireSSL=sessionProps->getBool("shireSSL");
// Process the post.
string cookie;
RPCError* status=NULL;
- ShibMLP markupProcessor(application);
+ ShibMLP markupProcessor;
markupProcessor.insert("requestURL", targeturl.c_str());
try {
status = shire.sessionCreate(elements.first,buf,cookie);
delete status;
// We've got a good session, set the cookie and redirect to target.
- cookie = string("Set-Cookie: ") + shib_cookie.second + '=' + cookie +
- (shib_cookie_props.first ? shib_cookie_props.second : "; path=/") + "\r\n"
+ cookie = string("Set-Cookie: ") + shib_cookie.first + '=' + cookie + shib_cookie.second + "\r\n"
"Location: " + elements.second + "\r\n"
"Expires: 01-Jan-1997 12:00:00 GMT\r\n"
"Cache-Control: private,no-store,no-cache\r\n"
}
catch (ShibTargetException &e) {
if (application) {
- ShibMLP markupProcessor(application);
+ ShibMLP markupProcessor;
markupProcessor.insert("requestURL", targeturl.c_str());
markupProcessor.insert("errorType", "Session Creation Service Error");
markupProcessor.insert("errorText", e.what());
#ifndef _DEBUG
catch (...) {
if (application) {
- ShibMLP markupProcessor(application);
+ ShibMLP markupProcessor;
markupProcessor.insert("requestURL", targeturl.c_str());
markupProcessor.insert("errorType", "Session Creation Service Error");
markupProcessor.insert("errorText", "Unexpected Exception");