###############################################################################
-Project: "adfs"=.\adfs\adfs.dsp - Package Owner=<4>
+Project: "adfs"=".\adfs\adfs.dsp" - Package Owner=<4>
Package=<5>
{{{
###############################################################################
-Project: "isapi_shib"=.\isapi_shib\isapi_shib.dsp - Package Owner=<4>
+Project: "isapi_shib"=".\isapi_shib\isapi_shib.dsp" - Package Owner=<4>
Package=<5>
{{{
###############################################################################
-Project: "mod_shib13"=.\apache\mod_shib13.dsp - Package Owner=<4>
+Project: "mod_shib13"=".\apache\mod_shib13.dsp" - Package Owner=<4>
Package=<5>
{{{
###############################################################################
-Project: "mod_shib20"=.\apache\mod_shib20.dsp - Package Owner=<4>
+Project: "mod_shib20"=".\apache\mod_shib20.dsp" - Package Owner=<4>
Package=<5>
{{{
###############################################################################
-Project: "mod_shib22"=.\apache\mod_shib22.dsp - Package Owner=<4>
+Project: "mod_shib22"=".\apache\mod_shib22.dsp" - Package Owner=<4>
Package=<5>
{{{
###############################################################################
-Project: "nsapi_shib"=.\nsapi_shib\nsapi_shib.dsp - Package Owner=<4>
+Project: "nsapi_shib"=".\nsapi_shib\nsapi_shib.dsp" - Package Owner=<4>
Package=<5>
{{{
###############################################################################
-Project: "oncrpc"=.\oncrpc\oncrpc.dsp - Package Owner=<4>
+Project: "oncrpc"=".\oncrpc\oncrpc.dsp" - Package Owner=<4>
Package=<5>
{{{
###############################################################################
-Project: "posttest"=.\posttest\posttest.dsp - Package Owner=<4>
+Project: "posttest"=".\posttest\posttest.dsp" - Package Owner=<4>
Package=<5>
{{{
###############################################################################
-Project: "shar"=.\shar\shar.dsp - Package Owner=<4>
+Project: "shar"=".\shar\shar.dsp" - Package Owner=<4>
Package=<5>
{{{
###############################################################################
-Project: "shib"=.\shib\shib.dsp - Package Owner=<4>
+Project: "shib"=".\shib\shib.dsp" - Package Owner=<4>
Package=<5>
{{{
###############################################################################
+Project: "shibauthorizer"=".\fastcgi\shibauthorizer.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name shibtarget
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "shibresponder"=".\fastcgi\shibresponder.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name shibtarget
+ End Project Dependency
+}}}
+
+###############################################################################
+
Project: "shibtarget"=".\shib-target\shibtarget.dsp" - Package Owner=<4>
Package=<5>
###############################################################################
-Project: "shibtest"=.\shibtest\shibtest.dsp - Package Owner=<4>
+Project: "shibtest"=".\shibtest\shibtest.dsp" - Package Owner=<4>
Package=<5>
{{{
###############################################################################
-Project: "siterefresh"=.\siterefresh\siterefresh.dsp - Package Owner=<4>
+Project: "siterefresh"=".\siterefresh\siterefresh.dsp" - Package Owner=<4>
Package=<5>
{{{
###############################################################################
-Project: "testclient"=.\shar\testclient.dsp - Package Owner=<4>
+Project: "testclient"=".\shar\testclient.dsp" - Package Owner=<4>
Package=<5>
{{{
###############################################################################
-Project: "xmlproviders"=.\xmlproviders\xmlproviders.dsp - Package Owner=<4>
+Project: "xmlproviders"=".\xmlproviders\xmlproviders.dsp" - Package Owner=<4>
Package=<5>
{{{
Package=<5>
{{{
- begin source code control
- "$/NSAPI", WNAAAAAA
- ..\..\..\..\documents and settings\cantor.2\my documents\projects\nsapi
- end source code control
}}}
Package=<3>
--- /dev/null
+/shibresponder___Win32_Debug
+/shibauthorizer___Win32_Release
+/shibauthorizer___Win32_Debug
+/shibresponder___Win32_Release
+/*.plg
--- /dev/null
+/*\r
+ * Copyright 2001-2007 Internet2\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/* shibauthorizer.cpp - Shibboleth FastCGI Authorizer\r
+\r
+ Andre Cruz\r
+*/\r
+\r
+// SAML Runtime\r
+#include <saml/saml.h>\r
+#include <shib-target/shib-target.h>\r
+\r
+#include <stdlib.h>\r
+#ifdef HAVE_UNISTD_H\r
+# include <unistd.h>\r
+# include <sys/mman.h>\r
+#endif\r
+#include <fcgio.h>\r
+\r
+using namespace shibtarget;\r
+using namespace saml;\r
+using namespace std;\r
+\r
+typedef enum {\r
+ SHIB_RETURN_OK,\r
+ SHIB_RETURN_KO,\r
+ SHIB_RETURN_DONE\r
+} shib_return_t;\r
+\r
+class ShibTargetFCGIAuth : public ShibTarget\r
+{\r
+ FCGX_Request* m_req;\r
+ string m_cookie;\r
+public:\r
+ map<string,string> m_headers;\r
+\r
+ ShibTargetFCGIAuth(FCGX_Request* req) : m_req(req) {\r
+ char* server_name_str = FCGX_GetParam("SHIBSP_SERVER_NAME", req->envp);\r
+ if (!server_name_str || !*server_name_str)\r
+ server_name_str = FCGX_GetParam("SERVER_NAME", req->envp);\r
+\r
+ char* server_port_str = FCGX_GetParam("SHIBSP_SERVER_PORT", req->envp);\r
+ if (!server_port_str || !*server_port_str)\r
+ server_port_str = FCGX_GetParam("SERVER_PORT", req->envp);\r
+ int server_port = strtol(server_port_str, &server_port_str, 10);\r
+ if (*server_port_str) {\r
+ cerr << "can't parse SERVER_PORT (" << FCGX_GetParam("SERVER_PORT", req->envp) << ")" << endl;\r
+ throw SAMLException("Unable to determine server port.");\r
+ }\r
+\r
+ char* server_scheme_str = FCGX_GetParam("SHIBSP_SERVER_SCHEME", req->envp);\r
+ if (!server_scheme_str || !*server_scheme_str)\r
+ server_scheme_str = (server_port == 443 || server_port == 8443) ? "https" : "http";\r
+\r
+ char* request_uri_str = FCGX_GetParam("REQUEST_URI", req->envp);\r
+ char* content_type_str = FCGX_GetParam("CONTENT_TYPE", req->envp);\r
+ char* remote_addr_str = FCGX_GetParam("REMOTE_ADDR", req->envp);\r
+ char* request_method_str = FCGX_GetParam("REQUEST_METHOD", req->envp);\r
+\r
+ init(server_scheme_str,\r
+ server_name_str,\r
+ server_port,\r
+ request_uri_str,\r
+ content_type_str ? content_type_str : "",\r
+ remote_addr_str,\r
+ request_method_str\r
+ );\r
+ }\r
+\r
+ ~ShibTargetFCGIAuth() { }\r
+\r
+ virtual void log(ShibLogLevel level, const string& msg) {\r
+ ShibTarget::log(level,msg);\r
+ if (level == LogLevelError)\r
+ cerr << "shib: " << msg;\r
+ }\r
+ \r
+ virtual string getCookies(void) const {\r
+ char* cookie = FCGX_GetParam("HTTP_COOKIE", m_req->envp);\r
+ return cookie ? cookie : "";\r
+ }\r
+ \r
+ virtual void setCookie(const string &name, const string &value) {\r
+ m_cookie += "Set-Cookie: " + name + "=" + value + "\r\n";\r
+ }\r
+\r
+ virtual string getArgs(void) {\r
+ char* args = FCGX_GetParam("QUERY_STRING", m_req->envp);\r
+ return args ? args : "";\r
+ }\r
+\r
+ virtual string getPostData(void) {\r
+ throw SAMLException("getPostData not implemented by FastCGI authorizer.");\r
+ }\r
+\r
+ virtual void clearHeader(const string& name) {\r
+ // no need, since request headers turn into actual environment variables\r
+ }\r
+ \r
+ virtual void setHeader(const string& name, const string &value) {\r
+ m_headers[name] = value;\r
+ }\r
+\r
+ virtual string getHeader(const string& name) {\r
+ if (m_headers.find(name) != m_headers.end())\r
+ return m_headers[name];\r
+ else\r
+ return "";\r
+ }\r
+\r
+ virtual void setRemoteUser(const string& user) {\r
+ m_headers["REMOTE_USER"] = user;\r
+ }\r
+\r
+ virtual string getRemoteUser(void) {\r
+ if (m_headers.find("REMOTE_USER") != m_headers.end())\r
+ return m_headers["REMOTE_USER"];\r
+ else {\r
+ char* remote_user = FCGX_GetParam("REMOTE_USER", m_req->envp);\r
+ if (remote_user)\r
+ return remote_user;\r
+ }\r
+ return "";\r
+ }\r
+\r
+ virtual void* sendPage(\r
+ const string& msg,\r
+ int code=200,\r
+ const string& content_type="text/html",\r
+ const Iterator<header_t>& headers=EMPTY(header_t)) {\r
+\r
+ string hdr = m_cookie + "Connection: close\r\nContent-type: " + content_type + "\r\n";\r
+ while (headers.hasNext()) {\r
+ const header_t& h=headers.next();\r
+ hdr += h.first + ": " + h.second + "\r\n";\r
+ }\r
+\r
+ // We can't return 200 OK here or else the filter is bypassed\r
+ // so custom Shib errors will get turned into a generic page.\r
+ const char* codestr="Status: 500 Server Error";\r
+ switch (code) {\r
+ case 403: codestr="Status: 403 Forbidden"; break;\r
+ case 404: codestr="Status: 404 Not Found"; break;\r
+ }\r
+\r
+ cout << codestr << "\r\n" << hdr << "\r\n" << msg;\r
+ return (void*)SHIB_RETURN_DONE;\r
+ }\r
+\r
+ virtual void* sendRedirect(const string& url) {\r
+ cout << "Status: 302 Please Wait" << "\r\n"\r
+ << "Location: " << url << "\r\n"\r
+ << m_cookie << "\r\n"\r
+ << "<HTML><BODY>Redirecting...</BODY></HTML>";\r
+ return (void*)SHIB_RETURN_DONE;\r
+ }\r
+\r
+ virtual void* returnDecline(void) { \r
+ return (void*)SHIB_RETURN_KO;\r
+ }\r
+\r
+ virtual void* returnOK(void) {\r
+ return (void*)SHIB_RETURN_OK;\r
+ }\r
+};\r
+\r
+static void print_ok(const map<string,string>& headers)\r
+{\r
+ cout << "Status: 200 OK" << "\r\n";\r
+ for (map<string,string>::const_iterator iter = headers.begin(); iter != headers.end(); iter++) {\r
+ cout << "Variable-" << iter->first << ": " << iter->second << "\r\n";\r
+ }\r
+ cout << "\r\n";\r
+}\r
+\r
+static void print_error(const char* msg)\r
+{\r
+ cout << "Status: 500 Server Error" << "\r\n\r\n" << msg;\r
+}\r
+\r
+int main(void)\r
+{\r
+ char* shib_config = getenv("SHIB_CONFIG");\r
+ char* shib_schema = getenv("SHIB_SCHEMA");\r
+ if ((shib_config == NULL) || (shib_schema == NULL)) {\r
+ cerr << "SHIB_CONFIG or SHIB_SCHEMA not initialized!" << endl;\r
+ exit(1);\r
+ }\r
+ cerr << "SHIB_CONFIG = " << shib_config << endl\r
+ << "SHIB_SCHEMA = " << shib_schema << endl;\r
+\r
+ ShibTargetConfig* g_Config;\r
+\r
+ try {\r
+ g_Config = &ShibTargetConfig::getConfig();\r
+ g_Config->setFeatures(\r
+ ShibTargetConfig::Listener |\r
+ ShibTargetConfig::Metadata |\r
+ ShibTargetConfig::AAP |\r
+ ShibTargetConfig::RequestMapper |\r
+ ShibTargetConfig::LocalExtensions |\r
+ ShibTargetConfig::Logging\r
+ );\r
+ if (!g_Config->init(shib_schema)) {\r
+ cerr << "failed to initialize Shibboleth libraries" << endl;\r
+ exit(1);\r
+ }\r
+ \r
+ if (!g_Config->load(shib_config)) {\r
+ cerr << "failed to load Shibboleth configuration" << endl;\r
+ exit(1);\r
+ }\r
+ }\r
+ catch (...) {\r
+ cerr << "exception while initializing Shibboleth configuration" << endl;\r
+ exit(1);\r
+ }\r
+\r
+ streambuf* cout_streambuf = cout.rdbuf();\r
+ streambuf* cerr_streambuf = cerr.rdbuf();\r
+\r
+ FCGX_Request request;\r
+\r
+ FCGX_Init();\r
+ FCGX_InitRequest(&request, 0, 0);\r
+ \r
+ cout << "Shibboleth initialization complete. Starting request loop." << endl;\r
+ while (FCGX_Accept_r(&request) == 0)\r
+ {\r
+ // Note that the default bufsize (0) will cause the use of iostream\r
+ // methods that require positioning (such as peek(), seek(),\r
+ // unget() and putback()) to fail (in favour of more efficient IO).\r
+ fcgi_streambuf cout_fcgi_streambuf(request.out);\r
+ fcgi_streambuf cerr_fcgi_streambuf(request.err);\r
+\r
+ cout.rdbuf(&cout_fcgi_streambuf);\r
+ cerr.rdbuf(&cerr_fcgi_streambuf);\r
+\r
+ try {\r
+ saml::NDC ndc("FastCGI shibauthorizer");\r
+ ShibTargetFCGIAuth sta(&request);\r
+ \r
+ pair<bool,void*> res = sta.doCheckAuthN();\r
+ if (res.first) {\r
+#ifdef _DEBUG\r
+ cerr << "shib: doCheckAuthN handled the request" << endl;\r
+#endif\r
+ switch((int)res.second) {\r
+ case SHIB_RETURN_OK:\r
+ print_ok(sta.m_headers);\r
+ continue;\r
+ \r
+ case SHIB_RETURN_KO:\r
+ print_ok(sta.m_headers);\r
+ continue;\r
+\r
+ case SHIB_RETURN_DONE:\r
+ continue;\r
+ \r
+ default:\r
+ cerr << "shib: doCheckAuthN returned an unexpected result: " << (int)res.second << endl;\r
+ print_error("<html><body>FastCGI Shibboleth authorizer returned an unexpected result.</body></html>");\r
+ continue;\r
+ }\r
+ }\r
+ \r
+ res = sta.doExportAssertions();\r
+ if (res.first) {\r
+#ifdef _DEBUG\r
+ cerr << "shib: doExportAssertions handled request" << endl;\r
+#endif\r
+ switch((int)res.second) {\r
+ case SHIB_RETURN_OK:\r
+ print_ok(sta.m_headers);\r
+ continue;\r
+ \r
+ case SHIB_RETURN_KO:\r
+ print_ok(sta.m_headers);\r
+ continue;\r
+\r
+ case SHIB_RETURN_DONE:\r
+ continue;\r
+ \r
+ default:\r
+ cerr << "shib: doExportAssertions returned an unexpected result: " << (int)res.second << endl;\r
+ print_error("<html><body>FastCGI Shibboleth authorizer returned an unexpected result.</body></html>");\r
+ continue;\r
+ }\r
+ }\r
+\r
+ res = sta.doCheckAuthZ();\r
+ if (res.first) {\r
+#ifdef _DEBUG\r
+ cerr << "shib: doCheckAuthZ handled request" << endl;\r
+#endif\r
+ switch((int)res.second) {\r
+ case SHIB_RETURN_OK:\r
+ print_ok(sta.m_headers);\r
+ continue;\r
+ \r
+ case SHIB_RETURN_KO:\r
+ print_ok(sta.m_headers);\r
+ continue;\r
+\r
+ case SHIB_RETURN_DONE:\r
+ continue;\r
+ \r
+ default:\r
+ cerr << "shib: doCheckAuthZ returned an unexpected result: " << (int)res.second << endl;\r
+ print_error("<html><body>FastCGI Shibboleth authorizer returned an unexpected result.</body></html>");\r
+ continue;\r
+ }\r
+ }\r
+\r
+ print_ok(sta.m_headers);\r
+ \r
+ }\r
+ catch (SAMLException& e) {\r
+ cerr << "shib: FastCGI authorizer caught an exception: " << e.what() << endl;\r
+ print_error("<html><body>FastCGI Shibboleth authorizer caught an exception, check log for details.</body></html>");\r
+ }\r
+\r
+ // If the output streambufs had non-zero bufsizes and\r
+ // were constructed outside of the accept loop (i.e.\r
+ // their destructor won't be called here), they would\r
+ // have to be flushed here.\r
+ }\r
+ cout << "Request loop ended." << endl;\r
+\r
+ cout.rdbuf(cout_streambuf);\r
+ cerr.rdbuf(cerr_streambuf);\r
+\r
+ if (g_Config)\r
+ g_Config->shutdown();\r
+ \r
+ return 0;\r
+}\r
--- /dev/null
+# Microsoft Developer Studio Project File - Name="shibauthorizer" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=shibauthorizer - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "shibauthorizer.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "shibauthorizer.mak" CFG="shibauthorizer - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "shibauthorizer - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "shibauthorizer - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF "$(CFG)" == "shibauthorizer - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "shibauthorizer___Win32_Release"\r
+# PROP Intermediate_Dir "shibauthorizer___Win32_Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I "." /I ".." /I "..\..\cpp-opensaml1" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 xerces-c_2.lib saml_5.lib libfcgi.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\cpp-opensaml1\saml\Release" /libpath:"\fcgi-2.4.0\libfcgi\Release"\r
+\r
+!ELSEIF "$(CFG)" == "shibauthorizer - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "shibauthorizer___Win32_Debug"\r
+# PROP BASE Intermediate_Dir "shibauthorizer___Win32_Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "shibauthorizer___Win32_Debug"\r
+# PROP Intermediate_Dir "shibauthorizer___Win32_Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /ZI /Od /I "." /I ".." /I "..\..\cpp-opensaml1" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 xerces-c_2D.lib saml_5D.lib libfcgi.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\cpp-opensaml1\saml\Debug" /libpath:"\fcgi-2.4.0\libfcgi\Debug"\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "shibauthorizer - Win32 Release"\r
+# Name "shibauthorizer - Win32 Debug"\r
+# Begin Source File\r
+\r
+SOURCE=.\shibauthorizer.cpp\r
+# End Source File\r
+# End Target\r
+# End Project\r
--- /dev/null
+/*\r
+ * Copyright 2001-2007 Internet2\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/* shibresponder.cpp - Shibboleth FastCGI Responder/Handler\r
+\r
+ Andre Cruz\r
+*/\r
+\r
+// SAML Runtime\r
+#include <saml/saml.h>\r
+#include <shib-target/shib-target.h>\r
+\r
+#include <stdlib.h>\r
+#ifdef HAVE_UNISTD_H\r
+# include <unistd.h>\r
+# include <sys/mman.h>\r
+#endif\r
+#include <fcgio.h>\r
+\r
+using namespace shibtarget;\r
+using namespace saml;\r
+using namespace std;\r
+\r
+typedef enum {\r
+ SHIB_RETURN_OK,\r
+ SHIB_RETURN_KO,\r
+ SHIB_RETURN_DONE\r
+} shib_return_t;\r
+\r
+class ShibTargetFCGI : public ShibTarget\r
+{\r
+ FCGX_Request* m_req;\r
+ char* m_body;\r
+ string m_cookie;\r
+ map<string, string> m_headers;\r
+\r
+public:\r
+ ShibTargetFCGI(FCGX_Request* req, char* post_data) : m_req(req), m_body(post_data) {\r
+\r
+ char* server_name_str = FCGX_GetParam("SHIBSP_SERVER_NAME", req->envp);\r
+ if (!server_name_str || !*server_name_str)\r
+ server_name_str = FCGX_GetParam("SERVER_NAME", req->envp);\r
+\r
+ char* server_port_str = FCGX_GetParam("SHIBSP_SERVER_PORT", req->envp);\r
+ if (!server_port_str || !*server_port_str)\r
+ server_port_str = FCGX_GetParam("SERVER_PORT", req->envp);\r
+ int server_port = strtol(server_port_str, &server_port_str, 10);\r
+ if (*server_port_str) {\r
+ cerr << "can't parse SERVER_PORT (" << FCGX_GetParam("SERVER_PORT", req->envp) << ")" << endl;\r
+ throw SAMLException("Unable to determine server port.");\r
+ }\r
+\r
+ char* server_scheme_str = FCGX_GetParam("SHIBSP_SERVER_SCHEME", req->envp);\r
+ if (!server_scheme_str || !*server_scheme_str)\r
+ server_scheme_str = (server_port == 443 || server_port == 8443) ? "https" : "http";\r
+\r
+ char* request_uri_str = FCGX_GetParam("REQUEST_URI", req->envp);\r
+ char* content_type_str = FCGX_GetParam("CONTENT_TYPE", req->envp);\r
+ char* remote_addr_str = FCGX_GetParam("REMOTE_ADDR", req->envp);\r
+ char* request_method_str = FCGX_GetParam("REQUEST_METHOD", req->envp);\r
+\r
+#ifdef _DEBUG\r
+ cerr << "server_name = " << server_name_str << endl\r
+ << "server_port = " << server_port << endl\r
+ << "request_uri_str = " << request_uri_str << endl\r
+ << "content_type = " << content_type_str << endl\r
+ << "remote_address = " << remote_addr_str << endl\r
+ << "request_method = " << request_method_str << endl;\r
+#endif\r
+\r
+ init(server_scheme_str,\r
+ server_name_str,\r
+ server_port,\r
+ request_uri_str,\r
+ content_type_str ? content_type_str : "",\r
+ remote_addr_str,\r
+ request_method_str\r
+ );\r
+ }\r
+\r
+ ~ShibTargetFCGI() { }\r
+\r
+ virtual void log(ShibLogLevel level, const string& msg) {\r
+ ShibTarget::log(level,msg);\r
+ \r
+ if (level == LogLevelError)\r
+ cerr << "shib: " << msg;\r
+ }\r
+ \r
+ virtual string getCookies(void) const {\r
+ char * cookie = FCGX_GetParam("HTTP_COOKIE", m_req->envp);\r
+ return cookie ? cookie : "";\r
+ }\r
+ \r
+ virtual void setCookie(const string& name, const string& value) {\r
+ m_cookie += "Set-Cookie: " + name + "=" + value + "\r\n";\r
+ }\r
+\r
+ virtual string getArgs(void) {\r
+ char * args = FCGX_GetParam("QUERY_STRING", m_req->envp);\r
+ return args ? args : "";\r
+ }\r
+\r
+ virtual string getPostData(void) {\r
+ return m_body ? m_body : "";\r
+ }\r
+\r
+ virtual void clearHeader(const string &name) {\r
+ throw SAMLException("clearHeader not implemented by FastCGI responder.");\r
+ }\r
+ \r
+ virtual void setHeader(const string &name, const string &value) {\r
+ throw SAMLException("setHeader not implemented by FastCGI responder.");\r
+ }\r
+\r
+ virtual string getHeader(const string &name) {\r
+ throw SAMLException("getHeader not implemented by FastCGI responder.");\r
+ }\r
+\r
+ virtual void setRemoteUser(const string &user) {\r
+ throw SAMLException("setRemoteUser not implemented by FastCGI responder.");\r
+ }\r
+\r
+ virtual string getRemoteUser(void) {\r
+ throw SAMLException("getRemoteUser not implemented by FastCGI responder.");\r
+ }\r
+\r
+ virtual void* sendPage(\r
+ const string& msg,\r
+ int code=200,\r
+ const string& content_type="text/html",\r
+ const Iterator<header_t>& headers=EMPTY(header_t)) {\r
+\r
+ string hdr = string ("Connection: close\r\nContent-type: ") + content_type + "\r\n" + m_cookie;\r
+ while (headers.hasNext()) {\r
+ const header_t& h=headers.next();\r
+ hdr += h.first + ": " + h.second + "\r\n";\r
+ }\r
+\r
+ const char* codestr="Status: 200 OK";\r
+ switch (code) {\r
+ case 500: codestr="Status: 500 Server Error"; break;\r
+ case 403: codestr="Status: 403 Forbidden"; break;\r
+ case 404: codestr="Status: 404 Not Found"; break;\r
+ }\r
+\r
+ cout << codestr << "\r\n" << hdr << m_cookie << "\r\n" << msg;\r
+ return (void*)SHIB_RETURN_DONE;\r
+ }\r
+\r
+ virtual void* sendRedirect(const string& url) {\r
+ cout << "Status: 302 Please Wait" << "\r\n" << "Location: " << url << "\r\n" << m_cookie << "\r\n"\r
+ << "<HTML><BODY>Redirecting...</BODY></HTML>";\r
+ return (void*)SHIB_RETURN_DONE;\r
+ }\r
+\r
+ virtual void* returnDecline(void) { \r
+ return (void*)SHIB_RETURN_KO;\r
+ }\r
+\r
+ virtual void* returnOK(void) {\r
+ return (void*)SHIB_RETURN_OK;\r
+ }\r
+};\r
+\r
+// Maximum number of bytes allowed to be read from stdin\r
+static const unsigned long STDIN_MAX = 1000000;\r
+\r
+static long gstdin(FCGX_Request* request, char** content)\r
+{\r
+ char* clenstr = FCGX_GetParam("CONTENT_LENGTH", request->envp);\r
+ unsigned long clen = STDIN_MAX;\r
+\r
+ if (clenstr) {\r
+ clen = strtol(clenstr, &clenstr, 10);\r
+ if (*clenstr) {\r
+ cerr << "can't parse CONTENT_LENGTH (" << FCGX_GetParam("CONTENT_LENGTH", request->envp) << ")" << endl;\r
+ clen = STDIN_MAX;\r
+ }\r
+\r
+ // *always* put a cap on the amount of data that will be read\r
+ if (clen > STDIN_MAX)\r
+ clen = STDIN_MAX;\r
+\r
+ *content = new char[clen];\r
+\r
+ cin.read(*content, clen);\r
+ clen = cin.gcount();\r
+ }\r
+ else {\r
+ // *never* read stdin when CONTENT_LENGTH is missing or unparsable\r
+ *content = 0;\r
+ clen = 0;\r
+ }\r
+\r
+ // Chew up any remaining stdin - this shouldn't be necessary\r
+ // but is because mod_fastcgi doesn't handle it correctly.\r
+\r
+ // ignore() doesn't set the eof bit in some versions of glibc++\r
+ // so use gcount() instead of eof()...\r
+ do cin.ignore(1024); while (cin.gcount() == 1024);\r
+\r
+ return clen;\r
+}\r
+\r
+static void print_ok() {\r
+ cout << "Status: 200 OK" << "\r\n\r\n";\r
+}\r
+\r
+static void print_error(const char* msg) {\r
+ cout << "Status: 500 Server Error" << "\r\n\r\n" << msg;\r
+}\r
+\r
+int main(void)\r
+{\r
+ char* shib_config = getenv("SHIB_CONFIG");\r
+ char* shib_schema = getenv("SHIB_SCHEMA");\r
+ if ((shib_config == NULL) || (shib_schema == NULL)) {\r
+ cerr << "SHIB_CONFIG or SHIB_SCHEMA not set." << endl;\r
+ exit(1);\r
+ }\r
+ cerr << "SHIB_CONFIG = " << shib_config << endl\r
+ << "SHIB_SCHEMA = " << shib_schema << endl;\r
+\r
+ ShibTargetConfig* g_Config;\r
+\r
+ try {\r
+ g_Config = &ShibTargetConfig::getConfig();\r
+ g_Config->setFeatures(\r
+ ShibTargetConfig::Listener |\r
+ ShibTargetConfig::Metadata |\r
+ ShibTargetConfig::RequestMapper |\r
+ ShibTargetConfig::LocalExtensions |\r
+ ShibTargetConfig::Logging\r
+ );\r
+ if (!g_Config->init(shib_schema)) {\r
+ cerr << "failed to initialize Shibboleth libraries" << endl;\r
+ exit(1);\r
+ }\r
+ \r
+ if (!g_Config->load(shib_config)) {\r
+ cerr << "failed to load Shibboleth configuration" << endl;\r
+ exit(1);\r
+ }\r
+ }\r
+ catch (...) {\r
+ cerr << "exception while initializing Shibboleth configuration" << endl;\r
+ exit(1);\r
+ }\r
+\r
+ streambuf* cin_streambuf = cin.rdbuf();\r
+ streambuf* cout_streambuf = cout.rdbuf();\r
+ streambuf* cerr_streambuf = cerr.rdbuf();\r
+\r
+ FCGX_Request request;\r
+\r
+ FCGX_Init();\r
+ FCGX_InitRequest(&request, 0, 0);\r
+ \r
+ cout << "Shibboleth initialization complete. Starting request loop." << endl;\r
+ while (FCGX_Accept_r(&request) == 0) {\r
+ // Note that the default bufsize (0) will cause the use of iostream\r
+ // methods that require positioning (such as peek(), seek(),\r
+ // unget() and putback()) to fail (in favour of more efficient IO).\r
+ fcgi_streambuf cin_fcgi_streambuf(request.in);\r
+ fcgi_streambuf cout_fcgi_streambuf(request.out);\r
+ fcgi_streambuf cerr_fcgi_streambuf(request.err);\r
+\r
+ cin.rdbuf(&cin_fcgi_streambuf);\r
+ cout.rdbuf(&cout_fcgi_streambuf);\r
+ cerr.rdbuf(&cerr_fcgi_streambuf);\r
+\r
+ // Although FastCGI supports writing before reading,\r
+ // many http clients (browsers) don't support it (so\r
+ // the connection deadlocks until a timeout expires!).\r
+ char* content;\r
+ gstdin(&request, &content);\r
+\r
+ try {\r
+ saml::NDC ndc("FastCGI shibresponder");\r
+ ShibTargetFCGI stf(&request, content);\r
+ \r
+ pair<bool,void*> res = stf.doHandler();\r
+ if (res.first) {\r
+#ifdef _DEBUG\r
+ cerr << "shib: doHandler handled the request" << endl;\r
+#endif\r
+ switch((int)res.second) {\r
+ case SHIB_RETURN_OK:\r
+ print_ok();\r
+ break;\r
+ \r
+ case SHIB_RETURN_KO:\r
+ cerr << "shib: doHandler failed to handle the request" << endl;\r
+ print_error("<html><body>FastCGI Shibboleth responder should only be used for Shibboleth protocol requests.</body></html>");\r
+ break;\r
+\r
+ case SHIB_RETURN_DONE:\r
+ // response already handled\r
+ break;\r
+ \r
+ default:\r
+ cerr << "shib: doHandler returned an unexpected result: " << (int)res.second << endl;\r
+ print_error("<html><body>FastCGI Shibboleth responder returned an unexpected result.</body></html>");\r
+ break;\r
+ }\r
+ }\r
+ else {\r
+ cerr << "shib: doHandler failed to handle request." << endl;\r
+ print_error("<html><body>FastCGI Shibboleth responder failed to process request.</body></html>");\r
+ } \r
+ \r
+ }\r
+ catch (SAMLException& e) {\r
+ cerr << "shib: FastCGI responder caught an exception: " << e.what() << endl;\r
+ print_error("<html><body>FastCGI Shibboleth responder caught an exception, check log for details.</body></html>");\r
+ }\r
+\r
+ delete[] content;\r
+\r
+ // If the output streambufs had non-zero bufsizes and\r
+ // were constructed outside of the accept loop (i.e.\r
+ // their destructor won't be called here), they would\r
+ // have to be flushed here.\r
+ }\r
+\r
+ cout << "Request loop ended." << endl;\r
+\r
+ cin.rdbuf(cin_streambuf);\r
+ cout.rdbuf(cout_streambuf);\r
+ cerr.rdbuf(cerr_streambuf);\r
+\r
+ if (g_Config)\r
+ g_Config->shutdown();\r
+ \r
+ return 0;\r
+}\r
--- /dev/null
+# Microsoft Developer Studio Project File - Name="shibresponder" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=shibresponder - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "shibresponder.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "shibresponder.mak" CFG="shibresponder - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "shibresponder - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "shibresponder - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF "$(CFG)" == "shibresponder - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "shibresponder___Win32_Release"\r
+# PROP Intermediate_Dir "shibresponder___Win32_Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I "." /I ".." /I "..\..\cpp-opensaml1" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 xerces-c_2.lib saml_5.lib libfcgi.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\cpp-opensaml1\saml\Release" /libpath:"\fcgi-2.4.0\libfcgi\Release"\r
+\r
+!ELSEIF "$(CFG)" == "shibresponder - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "shibresponder___Win32_Debug"\r
+# PROP BASE Intermediate_Dir "shibresponder___Win32_Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "shibresponder___Win32_Debug"\r
+# PROP Intermediate_Dir "shibresponder___Win32_Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /ZI /Od /I "." /I ".." /I "..\..\cpp-opensaml1" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 xerces-c_2D.lib saml_5D.lib libfcgi.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\cpp-opensaml1\saml\Debug" /libpath:"\fcgi-2.4.0\libfcgi\Debug"\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "shibresponder - Win32 Release"\r
+# Name "shibresponder - Win32 Debug"\r
+# Begin Source File\r
+\r
+SOURCE=.\shibresponder.cpp\r
+# End Source File\r
+# End Target\r
+# End Project\r