/*
* Copyright 2001-2007 Internet2
- *
+ *
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
/**
* isapi_shib.cpp
- *
+ *
* Shibboleth ISAPI filter
*/
#include <set>
#include <sstream>
#include <fstream>
+#include <stdexcept>
#include <process.h>
#include <windows.h>
static const XMLCh sslport[] = UNICODE_LITERAL_7(s,s,l,p,o,r,t);
static const XMLCh scheme[] = UNICODE_LITERAL_6(s,c,h,e,m,e);
static const XMLCh id[] = UNICODE_LITERAL_2(i,d);
- static const XMLCh ISAPI[] = UNICODE_LITERAL_5(I,S,A,P,I);
static const XMLCh Alias[] = UNICODE_LITERAL_5(A,l,i,a,s);
- static const XMLCh normalizeRequest[] = UNICODE_LITERAL_16(n,o,r,m,a,l,i,z,e,R,e,q,u,e,s,t);
static const XMLCh Site[] = UNICODE_LITERAL_4(S,i,t,e);
struct site_t {
string m_scheme,m_port,m_sslport,m_name;
set<string> m_aliases;
};
-
+
+ struct context_t {
+ char* m_user;
+ bool m_checked;
+ };
+
HINSTANCE g_hinstDLL;
SPConfig* g_Config = NULL;
map<string,site_t> g_Sites;
LPCSTR message)
{
LPCSTR messages[] = {message, NULL};
-
+
HANDLE hElog = RegisterEventSource(lpUNCServerName, "Shibboleth ISAPI Filter");
BOOL res = ReportEvent(hElog, wType, 0, dwEventID, lpUserSid, 1, 0, messages, NULL);
return (DeregisterEventSource(hElog) && res);
{
if (!pVer)
return FALSE;
-
+
if (!g_Config) {
LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL,
"Extension mode startup not possible, is the DLL loaded as a filter?");
return FALSE;
}
- LPCSTR config=getenv("SHIBSP_CONFIG");
- if (!config)
- config=SHIBSP_CONFIG;
-
try {
- DOMDocument* dummydoc=XMLToolingConfig::getConfig().getParser().newDocument();
- XercesJanitor<DOMDocument> docjanitor(dummydoc);
- DOMElement* dummy = dummydoc->createElementNS(NULL,path);
- auto_ptr_XMLCh src(config);
- dummy->setAttributeNS(NULL,path,src.get());
- dummy->setAttributeNS(NULL,validate,xmlconstants::XML_ONE);
-
- g_Config->setServiceProvider(g_Config->ServiceProviderManager.newPlugin(XML_SERVICE_PROVIDER,dummy));
- g_Config->getServiceProvider()->init();
+ if (!g_Config->instantiate(NULL, true))
+ throw runtime_error("unknown error");
}
catch (exception& ex) {
g_Config->term();
"Filter startup failed to load configuration, check native log for details.");
return FALSE;
}
-
+
// Access implementation-specifics and site mappings.
ServiceProvider* sp=g_Config->getServiceProvider();
Locker locker(sp);
else {
m_port = atoi(site.m_port.c_str());
}
-
+
// Scheme may come from site def or be derived from IIS.
m_scheme=site.m_scheme;
if (m_scheme.empty() || !g_bNormalizeRequest)
m_hostname = var;
if (site.m_name!=m_hostname && site.m_aliases.find(m_hostname)==site.m_aliases.end())
m_hostname=site.m_name;
+
+ if (!pfc->pFilterContext) {
+ pfc->pFilterContext = pfc->AllocMem(pfc, sizeof(context_t), NULL);
+ if (static_cast<context_t*>(pfc->pFilterContext)) {
+ static_cast<context_t*>(pfc->pFilterContext)->m_user = NULL;
+ static_cast<context_t*>(pfc->pFilterContext)->m_checked = false;
+ }
+ }
}
~ShibTargetIsapiF() { }
return 0;
}
string getRemoteAddr() const {
+ m_remote_addr = AbstractSPRequest::getRemoteAddr();
if (m_remote_addr.empty()) {
dynabuf var(16);
GetServerVariable(m_pfc,"REMOTE_ADDR",var,16,false);
LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, msg.c_str());
}
void clearHeader(const char* rawname, const char* cginame) {
- if (g_checkSpoofing) {
+ if (g_checkSpoofing && m_pfc->pFilterContext && !static_cast<context_t*>(m_pfc->pFilterContext)->m_checked) {
if (m_allhttp.empty())
GetServerVariable(m_pfc,"ALL_HTTP",m_allhttp,4096);
if (strstr(m_allhttp, cginame))
}
void setRemoteUser(const char* user) {
setHeader("remote-user", user);
+ if (m_pfc->pFilterContext) {
+ if (!user || !*user)
+ static_cast<context_t*>(m_pfc->pFilterContext)->m_user = NULL;
+ else if (static_cast<context_t*>(m_pfc->pFilterContext)->m_user = (char*)m_pfc->AllocMem(m_pfc, sizeof(char) * (strlen(user) + 1), NULL))
+ strcpy(static_cast<context_t*>(m_pfc->pFilterContext)->m_user, user);
+ }
}
string getRemoteUser() const {
return getHeader("remote-user");
const vector<string>& getClientCertificates() const {
return g_NoCerts;
}
-
+
// The filter never processes the POST, so stub these methods.
const char* getQueryString() const { throw IOException("getQueryString not implemented"); }
const char* getRequestBody() const { throw IOException("getRequestBody not implemented"); }
extern "C" DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificationType, LPVOID pvNotification)
{
// Is this a log notification?
- if (notificationType==SF_NOTIFY_LOG)
- {
- if (pfc->pFilterContext)
- ((PHTTP_FILTER_LOG)pvNotification)->pszClientUserName=static_cast<LPCSTR>(pfc->pFilterContext);
+ if (notificationType==SF_NOTIFY_LOG) {
+ if (pfc->pFilterContext && static_cast<context_t*>(pfc->pFilterContext)->m_user)
+ ((PHTTP_FILTER_LOG)pvNotification)->pszClientUserName=static_cast<context_t*>(pfc->pFilterContext)->m_user;
return SF_STATUS_REQ_NEXT_NOTIFICATION;
}
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;
-
+
ostringstream threadid;
threadid << "[" << getpid() << "] isapi_shib" << '\0';
xmltooling::NDC ndc(threadid.str().c_str());
// "false" because we don't override the Shib settings
pair<bool,long> res = stf.getServiceProvider().doAuthentication(stf);
+ if (pfc->pFilterContext)
+ static_cast<context_t*>(pfc->pFilterContext)->m_checked = true;
if (res.first) return res.second;
// "false" because we don't override the Shib settings
return WriteClientError(pfc,"Shibboleth Filter reached unreachable code, save my walrus!");
}
-
+
/****************************************************************************/
// ISAPI Extension
int m_port;
string m_scheme,m_hostname,m_uri;
mutable string m_remote_addr,m_remote_user;
-
+
public:
ShibTargetIsapiE(LPEXTENSION_CONTROL_BLOCK lpECB, const site_t& site)
: AbstractSPRequest(SHIBSP_LOGCAT".ISAPI"), m_lpECB(lpECB), m_gotBody(false) {
* the server is set up for proper PATH_INFO handling, or "IIS sucks rabid weasels mode",
* which is the default. No perfect way to tell, but we can take a good guess by checking
* whether the URL is a substring of the PATH_INFO:
- *
+ *
* e.g. for /Shibboleth.sso/SAML/POST
- *
+ *
* Bad mode (default):
* URL: /Shibboleth.sso
* PathInfo: /Shibboleth.sso/SAML/POST
- *
+ *
* Good mode:
* URL: /Shibboleth.sso
* PathInfo: /SAML/POST
*/
-
+
string uri;
// Clearly we're only in bad mode if path info exists at all.
else {
uri = url;
}
-
+
// For consistency with Apache, let's add the query string.
if (lpECB->lpszQueryString && *(lpECB->lpszQueryString)) {
uri += '?';
return m_remote_user;
}
string getRemoteAddr() const {
+ m_remote_addr = AbstractSPRequest::getRemoteAddr();
if (m_remote_addr.empty()) {
dynabuf var(16);
GetServerVariable(m_lpECB, "REMOTE_ADDR", var, 16, false);
if (m_lpECB->ServerSupportFunction(m_lpECB->ConnID, HSE_REQ_GET_CERT_INFO_EX, (LPVOID)&ccex, (LPDWORD)dwSize, NULL)) {
if (ccex.CertContext.cbCertEncoded) {
- unsigned int outlen;
+ xsecsize_t outlen;
XMLByte* serialized = Base64::encode(reinterpret_cast<XMLByte*>(CertificateBuf), ccex.CertContext.cbCertEncoded, &outlen);
m_certs.push_back(reinterpret_cast<char*>(serialized));
+#ifdef SHIBSP_XERCESC_HAS_XMLBYTE_RELEASE
XMLString::release(&serialized);
+#else
+ XMLString::release((char**)&serialized);
+#endif
}
}
}
ShibTargetIsapiE ste(lpECB, map_i->second);
pair<bool,long> res = ste.getServiceProvider().doHandler(ste);
if (res.first) return res.second;
-
+
return WriteClientError(lpECB, "Shibboleth Extension failed to process request");
}