Updating versions, working on new installer.
[shibboleth/cpp-sp.git] / isapi_shib / isapi_shib.cpp
index de35d5e..a84d748 100644 (file)
@@ -20,6 +20,7 @@
  * Shibboleth ISAPI filter
  */
 
+#define SHIBSP_LITE
 #include "config_win32.h"
 
 #define _CRT_NONSTDC_NO_DEPRECATE 1
@@ -33,6 +34,7 @@
 #include <xmltooling/util/NDC.h>
 #include <xmltooling/util/XMLConstants.h>
 #include <xmltooling/util/XMLHelper.h>
+#include <xercesc/util/Base64.hpp>
 #include <xercesc/util/XMLUniDefs.hpp>
 
 #include <set>
@@ -40,6 +42,7 @@
 #include <fstream>
 #include <process.h>
 
+#include <windows.h>
 #include <httpfilt.h>
 #include <httpext.h>
 
@@ -91,6 +94,9 @@ namespace {
     SPConfig* g_Config = NULL;
     map<string,site_t> g_Sites;
     bool g_bNormalizeRequest = true;
+    string g_unsetHeaderValue;
+    bool g_checkSpoofing = true;
+    vector<string> g_NoCerts;
 }
 
 BOOL LogEvent(
@@ -155,7 +161,6 @@ extern "C" BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer)
     g_Config->setFeatures(
         SPConfig::Listener |
         SPConfig::Caching |
-        SPConfig::Metadata |
         SPConfig::RequestMapping |
         SPConfig::InProcess |
         SPConfig::Logging
@@ -189,9 +194,15 @@ extern "C" BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer)
     
     // Access the implementation-specifics for site mappings.
     ServiceProvider* sp=g_Config->getServiceProvider();
-    xmltooling::Locker locker(sp);
-    const PropertySet* props=sp->getPropertySet("Local");
+    Locker locker(sp);
+    const PropertySet* props=sp->getPropertySet("InProcess");
     if (props) {
+        pair<bool,const char*> unsetValue=props->getString("unsetHeaderValue");
+        if (unsetValue.first)
+            g_unsetHeaderValue = unsetValue.second;
+        pair<bool,bool> checkSpoofing=props->getBool("checkSpoofing");
+        if (checkSpoofing.first && !checkSpoofing.second)
+            g_checkSpoofing = false;
         const DOMElement* impl=XMLHelper::getFirstChildElement(props->getElement(),Implementation);
         if (impl && (impl=XMLHelper::getFirstChildElement(impl,ISAPI))) {
             const XMLCh* flag=impl->getAttributeNS(NULL,normalizeRequest);
@@ -339,16 +350,14 @@ class ShibTargetIsapiF : public AbstractSPRequest
   PHTTP_FILTER_CONTEXT m_pfc;
   PHTTP_FILTER_PREPROC_HEADERS m_pn;
   map<string,string> m_headers;
-  vector<XSECCryptoX509*> m_certs;
   int m_port;
   string m_scheme,m_hostname,m_uri;
   mutable string m_remote_addr,m_content_type,m_method;
+  dynabuf m_allhttp;
 
 public:
-  ShibTargetIsapiF(PHTTP_FILTER_CONTEXT pfc, PHTTP_FILTER_PREPROC_HEADERS pn, const site_t& site) {
-
-    m_pfc = pfc;
-    m_pn = pn;
+  ShibTargetIsapiF(PHTTP_FILTER_CONTEXT pfc, PHTTP_FILTER_PREPROC_HEADERS pn, const site_t& site)
+      : m_pfc(pfc), m_pn(pn), m_allhttp(4096) {
 
     // URL path always come from IIS.
     dynabuf var(256);
@@ -428,10 +437,16 @@ public:
     if (level >= SPError)
         LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, msg.c_str());
   }
-  void clearHeader(const char* name) {
-    string hdr(!strcmp(name,"REMOTE_USER") ? "remote-user" : name);
+  void clearHeader(const char* rawname, const char* cginame) {
+    if (g_checkSpoofing) {
+        if (m_allhttp.empty())
+               GetServerVariable(m_pfc,"ALL_HTTP",m_allhttp,4096);
+        if (strstr(m_allhttp, cginame))
+            throw opensaml::SecurityPolicyException("Attempt to spoof header ($1) was detected.", params(1, rawname));
+    }
+    string hdr(!strcmp(rawname,"REMOTE_USER") ? "remote-user" : rawname);
     hdr += ':';
-    m_pn->SetHeader(m_pfc, const_cast<char*>(hdr.c_str()), "");
+    m_pn->SetHeader(m_pfc, const_cast<char*>(hdr.c_str()), const_cast<char*>(g_unsetHeaderValue.c_str()));
   }
   void setHeader(const char* name, const char* value) {
     string hdr(name);
@@ -441,8 +456,8 @@ public:
   string getHeader(const char* name) const {
     string hdr(name);
     hdr += ':';
-    dynabuf buf(1024);
-    GetHeader(m_pn, m_pfc, const_cast<char*>(hdr.c_str()), buf, 1024, false);
+    dynabuf buf(256);
+    GetHeader(m_pn, m_pfc, const_cast<char*>(hdr.c_str()), buf, 256, false);
     return string(buf);
   }
   void setRemoteUser(const char* user) {
@@ -465,9 +480,9 @@ public:
     hdr += "\r\n";
     const char* codestr="200 OK";
     switch (status) {
-        case SAML_HTTP_STATUS_FORBIDDEN:codestr="403 Forbidden"; break;
-        case SAML_HTTP_STATUS_NOTFOUND: codestr="404 Not Found"; break;
-        case SAML_HTTP_STATUS_ERROR:    codestr="500 Server Error"; break;
+        case XMLTOOLING_HTTP_STATUS_FORBIDDEN:codestr="403 Forbidden"; break;
+        case XMLTOOLING_HTTP_STATUS_NOTFOUND: codestr="404 Not Found"; break;
+        case XMLTOOLING_HTTP_STATUS_ERROR:    codestr="500 Server Error"; break;
     }
     m_pfc->ServerSupportFunction(m_pfc, SF_REQ_SEND_RESPONSE_HEADER, (void*)codestr, (DWORD)hdr.c_str(), 0);
     char buf[1024];
@@ -501,8 +516,8 @@ public:
     return SF_STATUS_REQ_NEXT_NOTIFICATION;
   }
 
-  const vector<XSECCryptoX509*>& getClientCertificates() const {
-      return m_certs;
+  const vector<string>& getClientCertificates() const {
+      return g_NoCerts;
   }
   
   // The filter never processes the POST, so stub these methods.
@@ -615,12 +630,12 @@ class ShibTargetIsapiE : public AbstractSPRequest
 {
   LPEXTENSION_CONTROL_BLOCK m_lpECB;
   map<string,string> m_headers;
-  vector<XSECCryptoX509*> m_certs;
+  mutable vector<string> m_certs;
   mutable string m_body;
   mutable bool m_gotBody;
   int m_port;
   string m_scheme,m_hostname,m_uri;
-  mutable string m_remote_addr;
+  mutable string m_remote_addr,m_remote_user;
   
 public:
   ShibTargetIsapiE(LPEXTENSION_CONTROL_BLOCK lpECB, const site_t& site) : m_lpECB(lpECB), m_gotBody(false) {
@@ -716,6 +731,15 @@ public:
   long getContentLength() const {
       return m_lpECB->cbTotalBytes;
   }
+  string getRemoteUser() const {
+    if (m_remote_user.empty()) {
+        dynabuf var(16);
+        GetServerVariable(m_lpECB, "REMOTE_USER", var, 32, false);
+        if (!var.empty())
+            m_remote_user = var;
+    }
+    return m_remote_user;
+  }
   string getRemoteAddr() const {
     if (m_remote_addr.empty()) {
         dynabuf var(16);
@@ -725,7 +749,7 @@ public:
     }
     return m_remote_addr;
   }
-  void log(SPLogLevel level, const string& msg) {
+  void log(SPLogLevel level, const string& msg) const {
       AbstractSPRequest::log(level,msg);
       if (level >= SPError)
           LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, msg.c_str());
@@ -783,9 +807,9 @@ public:
     hdr += "\r\n";
     const char* codestr="200 OK";
     switch (status) {
-        case SAML_HTTP_STATUS_FORBIDDEN:codestr="403 Forbidden"; break;
-        case SAML_HTTP_STATUS_NOTFOUND: codestr="404 Not Found"; break;
-        case SAML_HTTP_STATUS_ERROR:    codestr="500 Server Error"; break;
+        case XMLTOOLING_HTTP_STATUS_FORBIDDEN:codestr="403 Forbidden"; break;
+        case XMLTOOLING_HTTP_STATUS_NOTFOUND: codestr="404 Not Found"; break;
+        case XMLTOOLING_HTTP_STATUS_ERROR:    codestr="500 Server Error"; break;
     }
     m_lpECB->ServerSupportFunction(m_lpECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, (void*)codestr, 0, (LPDWORD)hdr.c_str());
     char buf[1024];
@@ -824,15 +848,30 @@ public:
       return HSE_STATUS_SUCCESS;
   }
 
-  const vector<XSECCryptoX509*>& getClientCertificates() const {
+  const vector<string>& getClientCertificates() const {
+      if (m_certs.empty()) {
+        char CertificateBuf[8192];
+        CERT_CONTEXT_EX ccex;
+        ccex.cbAllocated = sizeof(CertificateBuf);
+        ccex.CertContext.pbCertEncoded = (BYTE*)CertificateBuf;
+        DWORD dwSize = sizeof(ccex);
+
+        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;
+                XMLByte* serialized = Base64::encode(reinterpret_cast<XMLByte*>(CertificateBuf), ccex.CertContext.cbCertEncoded, &outlen);
+                m_certs.push_back(reinterpret_cast<char*>(serialized));
+                XMLString::release(&serialized);
+            }
+        }
+      }
       return m_certs;
   }
 
   // Not used in the extension.
-  virtual void clearHeader(const char* name) { throw runtime_error("clearHeader not implemented"); }
-  virtual void setHeader(const char* name, const char* value) { throw runtime_error("setHeader not implemented"); }
-  virtual void setRemoteUser(const char* user) { throw runtime_error("setRemoteUser not implemented"); }
-  virtual string getRemoteUser() const { throw runtime_error("getRemoteUser not implemented"); }
+  void clearHeader(const char* rawname, const char* cginame) { throw runtime_error("clearHeader not implemented"); }
+  void setHeader(const char* name, const char* value) { throw runtime_error("setHeader not implemented"); }
+  void setRemoteUser(const char* user) { throw runtime_error("setRemoteUser not implemented"); }
 };
 
 extern "C" DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB)