From 6809eb5a6ad3f6bac52e2bc1f770d580db396454 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Sat, 20 Oct 2007 05:31:06 +0000 Subject: [PATCH] Port fastcgi code to trunk. Move loadable modules from libexec to lib/shibboleth. --- .cproject | 2 + Shibboleth.sln | 35 +++ adfs/Makefile.am | 4 +- apache/Makefile.am | 8 +- apache/mod_shib13.vcproj | 2 - configs/Makefile.am | 3 +- configs/apache.config.in | 2 +- configs/apache2.config.in | 2 +- configs/apache22.config.in | 2 +- configs/shibboleth2.xml.in | 6 +- configure.ac | 35 +++ fastcgi/.gitignore | 5 + fastcgi/Makefile.am | 23 ++ fastcgi/shibauthorizer.cpp | 411 ++++++++++++++++++++++++++++++++ fastcgi/shibauthorizer.vcproj | 217 +++++++++++++++++ fastcgi/shibresponder.cpp | 413 +++++++++++++++++++++++++++++++++ fastcgi/shibresponder.vcproj | 217 +++++++++++++++++ isapi_shib/isapi_shib.vcproj | 2 - msi/scripts/shib_edit_config_files.vbs | 8 +- nsapi_shib/Makefile.am | 3 +- nsapi_shib/nsapi_shib.vcproj | 2 - odbc-store/Makefile.am | 2 +- 22 files changed, 1376 insertions(+), 28 deletions(-) create mode 100644 fastcgi/.gitignore create mode 100644 fastcgi/Makefile.am create mode 100644 fastcgi/shibauthorizer.cpp create mode 100644 fastcgi/shibauthorizer.vcproj create mode 100644 fastcgi/shibresponder.cpp create mode 100644 fastcgi/shibresponder.vcproj diff --git a/.cproject b/.cproject index 327af9d..eb08f9e 100644 --- a/.cproject +++ b/.cproject @@ -14,6 +14,7 @@ + @@ -40,6 +41,7 @@ + diff --git a/Shibboleth.sln b/Shibboleth.sln index fa59987..c4616c3 100644 --- a/Shibboleth.sln +++ b/Shibboleth.sln @@ -126,6 +126,30 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "resolvertest", "util\resolv {81F0F7A6-DC36-46EF-957F-F9E81D4403F6} = {81F0F7A6-DC36-46EF-957F-F9E81D4403F6} EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "fastcgi", "fastcgi", "{8E1AF2CF-24E1-4983-8681-394D89DF9AD2}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shibauthorizer", "fastcgi\shibauthorizer.vcproj", "{8CF7DDFA-EAA0-416E-853E-3DCB210C4AE0}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {81F0F7A6-DC36-46EF-957F-F9E81D4403F7} = {81F0F7A6-DC36-46EF-957F-F9E81D4403F7} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shibresponder", "fastcgi\shibresponder.vcproj", "{B2423DCE-048D-4BAA-9AB9-F5D1FCDD3D25}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {81F0F7A6-DC36-46EF-957F-F9E81D4403F7} = {81F0F7A6-DC36-46EF-957F-F9E81D4403F7} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -184,6 +208,14 @@ Global {F13141B6-6C87-40BB-8D4E-5CC56EBB4C59}.Debug|Win32.Build.0 = Debug|Win32 {F13141B6-6C87-40BB-8D4E-5CC56EBB4C59}.Release|Win32.ActiveCfg = Release|Win32 {F13141B6-6C87-40BB-8D4E-5CC56EBB4C59}.Release|Win32.Build.0 = Release|Win32 + {8CF7DDFA-EAA0-416E-853E-3DCB210C4AE0}.Debug|Win32.ActiveCfg = Debug|Win32 + {8CF7DDFA-EAA0-416E-853E-3DCB210C4AE0}.Debug|Win32.Build.0 = Debug|Win32 + {8CF7DDFA-EAA0-416E-853E-3DCB210C4AE0}.Release|Win32.ActiveCfg = Release|Win32 + {8CF7DDFA-EAA0-416E-853E-3DCB210C4AE0}.Release|Win32.Build.0 = Release|Win32 + {B2423DCE-048D-4BAA-9AB9-F5D1FCDD3D25}.Debug|Win32.ActiveCfg = Debug|Win32 + {B2423DCE-048D-4BAA-9AB9-F5D1FCDD3D25}.Debug|Win32.Build.0 = Debug|Win32 + {B2423DCE-048D-4BAA-9AB9-F5D1FCDD3D25}.Release|Win32.ActiveCfg = Release|Win32 + {B2423DCE-048D-4BAA-9AB9-F5D1FCDD3D25}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -194,10 +226,13 @@ Global {1396D80A-8672-4224-9B02-95F3F4207CDB} = {26BA8F84-6E42-41FA-9B13-5D3F4B5B2050} {B44C0852-83B8-4FB2-A86E-097C9C8256D0} = {26BA8F84-6E42-41FA-9B13-5D3F4B5B2050} {87C25D4E-8D19-4513-B0BA-BC668BC2DEE3} = {26BA8F84-6E42-41FA-9B13-5D3F4B5B2050} + {8E1AF2CF-24E1-4983-8681-394D89DF9AD2} = {26BA8F84-6E42-41FA-9B13-5D3F4B5B2050} {666A63A7-983F-4C19-8411-207F24305197} = {96AE4FC9-45EF-4C18-9F3B-EDA439E26E4C} {26D4FABF-ACDE-4947-9C4A-7AE1B50CD83A} = {96AE4FC9-45EF-4C18-9F3B-EDA439E26E4C} {26D4FABF-ACDE-4947-9C4A-7AE1B50CD83B} = {96AE4FC9-45EF-4C18-9F3B-EDA439E26E4C} {F13141B6-6C87-40BB-8D4E-5CC56EBB4C5A} = {FED80230-119E-4B2F-9F53-D2660A5F022B} {F13141B6-6C87-40BB-8D4E-5CC56EBB4C59} = {FED80230-119E-4B2F-9F53-D2660A5F022B} + {8CF7DDFA-EAA0-416E-853E-3DCB210C4AE0} = {8E1AF2CF-24E1-4983-8681-394D89DF9AD2} + {B2423DCE-048D-4BAA-9AB9-F5D1FCDD3D25} = {8E1AF2CF-24E1-4983-8681-394D89DF9AD2} EndGlobalSection EndGlobal diff --git a/adfs/Makefile.am b/adfs/Makefile.am index 8c16b49..82913b5 100644 --- a/adfs/Makefile.am +++ b/adfs/Makefile.am @@ -1,8 +1,6 @@ -## $Id$ - AUTOMAKE_OPTIONS = foreign -plugindir = $(libexecdir) +plugindir = $(libdir)/@PACKAGE@ plugin_LTLIBRARIES = adfs.la adfs-lite.la adfs_la_LIBADD = \ diff --git a/apache/Makefile.am b/apache/Makefile.am index 2269592..805ebed 100644 --- a/apache/Makefile.am +++ b/apache/Makefile.am @@ -1,9 +1,7 @@ -## $Id$ - AUTOMAKE_OPTIONS = foreign if BUILD_AP13 -modshib13dir = $(libexecdir) +modshib13dir = $(libdir)/@PACKAGE@ modshib13_LTLIBRARIES = mod_shib_13.la mod_shib_13_la_SOURCES = mod_shib_13.cpp mod_shib_13_la_CXXFLAGS = $(APXS_CFLAGS) -I$(APXS_INCLUDE) @@ -17,7 +15,7 @@ install-exec-hook: endif if BUILD_AP20 -modshib20dir = $(libexecdir) +modshib20dir = $(libdir)/@PACKAGE@ modshib20_LTLIBRARIES = mod_shib_20.la mod_shib_20_la_SOURCES = mod_shib_20.cpp mod_shib_20_la_CXXFLAGS = $(APXS2_CFLAGS) -I$(APXS2_INCLUDE) @@ -31,7 +29,7 @@ install-exec-hook: endif if BUILD_AP22 -modshib22dir = $(libexecdir) +modshib22dir = $(libdir)/@PACKAGE@ modshib22_LTLIBRARIES = mod_shib_22.la mod_shib_22_la_SOURCES = mod_shib_22.cpp mod_shib_22_la_CXXFLAGS = $(APXS22_CFLAGS) -I$(APXS22_INCLUDE) diff --git a/apache/mod_shib13.vcproj b/apache/mod_shib13.vcproj index 9989077..c259b88 100644 --- a/apache/mod_shib13.vcproj +++ b/apache/mod_shib13.vcproj @@ -53,7 +53,6 @@ StringPooling="true" RuntimeLibrary="2" EnableFunctionLevelLinking="true" - RuntimeTypeInfo="true" WarningLevel="3" SuppressStartupBanner="true" Detect64BitPortabilityProblems="true" @@ -144,7 +143,6 @@ PreprocessorDefinitions="_WINDOWS;EAPI;WIN32;_DEBUG" BasicRuntimeChecks="3" RuntimeLibrary="3" - RuntimeTypeInfo="true" BrowseInformation="1" WarningLevel="3" SuppressStartupBanner="true" diff --git a/configs/Makefile.am b/configs/Makefile.am index 4d798b4..6fb2487 100644 --- a/configs/Makefile.am +++ b/configs/Makefile.am @@ -2,6 +2,7 @@ AUTOMAKE_OPTIONS = foreign +pkglibdir = ${libdir}/@PACKAGE@ pkglogdir = ${localstatedir}/log/@PACKAGE@ pkgdocdir = ${datadir}/doc/@PACKAGE@ shirelogdir = ${localstatedir}/log/httpd @@ -51,7 +52,7 @@ do-build-file: rm -f ${FILE}.tmp sed < ${srcdir}/${FILE}.in > ${FILE}.tmp \ -e 's:@-PREFIX-@:${prefix}:g' \ - -e 's:@-LIBEXECDIR-@:${libexecdir}:g' \ + -e 's:@-PKGLIBDIR-@:${pkglibdir}:g' \ -e 's:@-PKGSYSCONFDIR-@:${pkgsysconfdir}:g' \ -e 's:@-PKGXMLDIR-@:${pkgxmldir}:g' \ -e 's:@-PKGDOCDIR-@:${pkgdocdir}:g' \ diff --git a/configs/apache.config.in b/configs/apache.config.in index bfe69ef..12e058e 100644 --- a/configs/apache.config.in +++ b/configs/apache.config.in @@ -7,7 +7,7 @@ # # Load the Shibboleth module. # -LoadModule mod_shib @-LIBEXECDIR-@/mod_shib_13.so +LoadModule mod_shib @-PKGLIBDIR-@/mod_shib_13.so # # Global Configuration diff --git a/configs/apache2.config.in b/configs/apache2.config.in index c9ff93b..09dd45d 100644 --- a/configs/apache2.config.in +++ b/configs/apache2.config.in @@ -7,7 +7,7 @@ # # Load the SHIBBOLETH module # -LoadModule mod_shib @-LIBEXECDIR-@/mod_shib_20.so +LoadModule mod_shib @-PKGLIBDIR-@/mod_shib_20.so # # Global Configuration diff --git a/configs/apache22.config.in b/configs/apache22.config.in index b913f88..134f8f2 100644 --- a/configs/apache22.config.in +++ b/configs/apache22.config.in @@ -7,7 +7,7 @@ # # Load the SHIBBOLETH module # -LoadModule mod_shib @-LIBEXECDIR-@/mod_shib_22.so +LoadModule mod_shib @-PKGLIBDIR-@/mod_shib_22.so # # Global Configuration diff --git a/configs/shibboleth2.xml.in b/configs/shibboleth2.xml.in index 18a6ba3..ceafe44 100644 --- a/configs/shibboleth2.xml.in +++ b/configs/shibboleth2.xml.in @@ -12,8 +12,8 @@ @@ -44,7 +44,7 @@ diff --git a/configure.ac b/configure.ac index 0e335ac..2ecdf6d 100644 --- a/configure.ac +++ b/configure.ac @@ -294,6 +294,41 @@ if test ! "$WANT_NSAPI" = "no" ; then WANT_SUBDIRS="$WANT_SUBDIRS nsapi_shib" fi + +# +# Build FastCGI support? +# +AC_MSG_CHECKING(for FastCGI support) +AC_ARG_WITH(fastcgi, + AC_HELP_STRING([--with-fastcgi=DIR], [Build FastCGI support]), + [WANT_FASTCGI=$withval],[WANT_FASTCGI=no]) +AC_MSG_RESULT($WANT_FASTCGI) + +if test "$WANT_FASTCGI" != "no"; then + if test "$WANT_FASTCGI" != "yes"; then + if test x_$WANT_FASTCGI != x_/usr; then + FASTCGI_INCLUDE="-I$WANT_FASTCGI/include" + FASTCGI_LDFLAGS="-L$WANT_FASTCGI/lib" + fi + fi + AC_CHECK_HEADER([fcgio.h],, + AC_MSG_ERROR([unable to find FastCGI header files])) + FASTCGI_LIBS="-lfcgi -lfcgi++" +fi + +AC_SUBST(FASTCGI_INCLUDE) +AC_SUBST(FASTCGI_LDFLAGS) +AC_SUBST(FASTCGI_LIBS) + +# always output the Makefile, even if you don't use it +AC_CONFIG_FILES([fastcgi/Makefile]) +AM_CONDITIONAL(BUILD_FASTCGI,test ! "$WANT_FASTCGI" = "no") + +if test ! "$WANT_FASTCGI" = "no" ; then + WANT_SUBDIRS="$WANT_SUBDIRS fastcgi" +fi + + # # If no --enable-apache-xx specified # find a default and fake the specific parameters diff --git a/fastcgi/.gitignore b/fastcgi/.gitignore new file mode 100644 index 0000000..90c669f --- /dev/null +++ b/fastcgi/.gitignore @@ -0,0 +1,5 @@ +/*.user +/shibauthorizer___Win32_Debug +/shibresponder___Win32_Debug +/shibauthorizer___Win32_Release +/shibresponder___Win32_Release diff --git a/fastcgi/Makefile.am b/fastcgi/Makefile.am new file mode 100644 index 0000000..ba460a2 --- /dev/null +++ b/fastcgi/Makefile.am @@ -0,0 +1,23 @@ +AUTOMAKE_OPTIONS = foreign + +if BUILD_FASTCGI + +fastcgidir = $(libdir)/@PACKAGE@ + +fastcgi_PROGRAMS = shibauthorizer shibresponder + +shibauthorizer_SOURCES = shibauthorizer.cpp +shibauthorizer_CXXFLAGS = -I$(FASTCGI_INCLUDE) +shibauthorizer_LDFLAGS = $(FASTCGI_LDFLAGS) $(FASTCGI_LIBS) +shibauthorizer_LDADD = \ + $(top_builddir)/shibsp/libshibsp-lite.la + +shibresponder_SOURCES = shibresponder.cpp +shibresponder_CXXFLAGS = -I$(FASTCGI_INCLUDE) +shibresponder_LDFLAGS = $(FASTCGI_LDFLAGS) $(FASTCGI_LIBS) +shibresponder_LDADD = \ + $(top_builddir)/shibsp/libshibsp-lite.la + +endif + +EXTRA_DIST = shibauthorizer.cpp shibresponder.cpp shibauthorizer.vcproj shibresponder.vcproj diff --git a/fastcgi/shibauthorizer.cpp b/fastcgi/shibauthorizer.cpp new file mode 100644 index 0000000..5395172 --- /dev/null +++ b/fastcgi/shibauthorizer.cpp @@ -0,0 +1,411 @@ +/* + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* shibauthorizer.cpp - Shibboleth FastCGI Authorizer + + Andre Cruz +*/ + +#define SHIBSP_LITE +#include "config_win32.h" + +#define _CRT_NONSTDC_NO_DEPRECATE 1 +#define _CRT_SECURE_NO_DEPRECATE 1 +#define _SCL_SECURE_NO_WARNINGS 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#ifdef HAVE_UNISTD_H +# include +# include +#endif +#include + +using namespace shibsp; +using namespace xmltooling; +using namespace xercesc; +using namespace std; + +static const XMLCh path[] = UNICODE_LITERAL_4(p,a,t,h); +static const XMLCh validate[] = UNICODE_LITERAL_8(v,a,l,i,d,a,t,e); + +typedef enum { + SHIB_RETURN_OK, + SHIB_RETURN_KO, + SHIB_RETURN_DONE +} shib_return_t; + +class ShibTargetFCGIAuth : public AbstractSPRequest +{ + FCGX_Request* m_req; + int m_port; + string m_scheme,m_hostname; + multimap m_response_headers; +public: + map m_request_headers; + + ShibTargetFCGIAuth(FCGX_Request* req, const char* scheme=NULL, const char* hostname=NULL, int port=0) : m_req(req) { + const char* server_name_str = hostname; + if (!server_name_str || !*server_name_str) + server_name_str = FCGX_GetParam("SERVER_NAME", req->envp); + m_hostname = server_name_str; + + m_port = port; + if (!m_port) { + char* server_port_str = FCGX_GetParam("SERVER_PORT", req->envp); + m_port = strtol(server_port_str, &server_port_str, 10); + if (*server_port_str) { + cerr << "can't parse SERVER_PORT (" << FCGX_GetParam("SERVER_PORT", req->envp) << ")" << endl; + throw exception("Unable to determine server port."); + } + } + + const char* server_scheme_str = scheme; + if (!server_scheme_str || !*server_scheme_str) + server_scheme_str = (m_port == 443 || m_port == 8443) ? "https" : "http"; + m_scheme = server_scheme_str; + } + + ~ShibTargetFCGIAuth() { } + + const char* getScheme() const { + return m_scheme.c_str(); + } + const char* getHostname() const { + return m_hostname.c_str(); + } + int getPort() const { + return m_port; + } + const char* getRequestURI() const { + return FCGX_GetParam("REQUEST_URI", m_req->envp); + } + const char* getMethod() const { + return FCGX_GetParam("REQUEST_METHOD", m_req->envp); + } + string getContentType() const { + const char* s = FCGX_GetParam("CONTENT_TYPE", m_req->envp); + return s ? s : ""; + } + long getContentLength() const { + const char* s = FCGX_GetParam("CONTENT_LENGTH", m_req->envp); + return s ? atol(s) : 0; + } + string getRemoteAddr() const { + const char* s = FCGX_GetParam("REMOTE_ADDR", m_req->envp); + return s ? s : ""; + } + void log(SPLogLevel level, const string& msg) const { + AbstractSPRequest::log(level,msg); + if (level >= SPError) + cerr << "shib: " << msg; + } + void clearHeader(const char* rawname, const char* cginame) { + // no need, since request headers turn into actual environment variables + } + void setHeader(const char* name, const char* value) { + if (value) + m_request_headers[name] = value; + else + m_request_headers.erase(name); + } + virtual string getHeader(const char* name) const { + map::const_iterator i = m_request_headers.find(name); + if (i != m_request_headers.end()) + return i->second; + else + return ""; + } + void setRemoteUser(const char* user) { + if (user) + m_request_headers["REMOTE_USER"] = user; + else + m_request_headers.erase("REMOTE_USER"); + } + string getRemoteUser() const { + map::const_iterator i = m_request_headers.find("REMOTE_USER"); + if (i != m_request_headers.end()) + return i->second; + else { + char* remote_user = FCGX_GetParam("REMOTE_USER", m_req->envp); + if (remote_user) + return remote_user; + } + return ""; + } + void setResponseHeader(const char* name, const char* value) { + // Set for later. + if (value) + m_response_headers.insert(make_pair(name,value)); + else + m_response_headers.erase(name); + } + const char* getQueryString() const { + return FCGX_GetParam("QUERY_STRING", m_req->envp); + } + const char* getRequestBody() const { + throw exception("getRequestBody not implemented by FastCGI authorizer."); + } + + long sendResponse(istream& in, long status) { + string hdr = string("Connection: close\r\n"); + for (multimap::const_iterator i=m_response_headers.begin(); i!=m_response_headers.end(); ++i) + hdr += i->first + ": " + i->second + "\r\n"; + + // We can't return 200 OK here or else the filter is bypassed + // so custom Shib errors will get turned into a generic page. + const char* codestr="Status: 500 Server Error"; + switch (status) { + case XMLTOOLING_HTTP_STATUS_FORBIDDEN: codestr="Status: 403 Forbidden"; break; + case XMLTOOLING_HTTP_STATUS_NOTFOUND: codestr="Status: 404 Not Found"; break; + } + cout << codestr << "\r\n" << hdr << "\r\n"; + char buf[1024]; + while (in) { + in.read(buf,1024); + cout.write(buf, in.gcount()); + } + return SHIB_RETURN_DONE; + } + + long sendRedirect(const char* url) { + string hdr=string("Status: 302 Please Wait\r\nLocation: ") + url + "\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 40\r\n" + "Expires: 01-Jan-1997 12:00:00 GMT\r\n" + "Cache-Control: private,no-store,no-cache\r\n"; + for (multimap::const_iterator i=m_response_headers.begin(); i!=m_response_headers.end(); ++i) + hdr += i->first + ": " + i->second + "\r\n"; + hdr += "\r\n"; + + cout << hdr << "Redirecting..."; + return SHIB_RETURN_DONE; + } + + long returnDecline() { + return SHIB_RETURN_KO; + } + + long returnOK() { + return SHIB_RETURN_OK; + } + + const vector& getClientCertificates() const { + static vector g_NoCerts; + return g_NoCerts; + } +}; + +static void print_ok(const map& headers) +{ + cout << "Status: 200 OK" << "\r\n"; + for (map::const_iterator iter = headers.begin(); iter != headers.end(); iter++) { + cout << "Variable-" << iter->first << ": " << iter->second << "\r\n"; + } + cout << "\r\n"; +} + +static void print_error(const char* msg) +{ + cout << "Status: 500 Server Error" << "\r\n\r\n" << msg; +} + +int main(void) +{ + const char* schemadir=getenv("SHIBSP_SCHEMAS"); + if (!schemadir) + schemadir=SHIBSP_SCHEMAS; + const char* config=getenv("SHIBSP_CONFIG"); + if (!config) + config=SHIBSP_CONFIG; + + cerr << "SHIBSP_CONFIG = " << config << endl + << "SHIBSP_SCHEMAS = " << schemadir << endl; + + SPConfig* g_Config=&SPConfig::getConfig(); + g_Config->setFeatures( + SPConfig::Listener | + SPConfig::Caching | + SPConfig::RequestMapping | + SPConfig::InProcess | + SPConfig::Logging | + SPConfig::Handlers + ); + if (!g_Config->init(schemadir)) { + cerr << "failed to initialize Shibboleth libraries" << endl; + exit(1); + } + + try { + DOMDocument* dummydoc=XMLToolingConfig::getConfig().getParser().newDocument(); + XercesJanitor 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(); + } + catch (exception& ex) { + g_Config->term(); + cerr << "exception while initializing Shibboleth configuration: " << ex.what() << endl; + exit(1); + } + + string g_ServerScheme; + string g_ServerName; + int g_ServerPort=0; + + // Load "authoritative" URL fields. + char* var = getenv("SHIBSP_SERVER_NAME"); + if (var) + g_ServerName = var; + var = getenv("SHIBSP_SERVER_SCHEME"); + if (var) + g_ServerScheme = var; + var = getenv("SHIBSP_SERVER_PORT"); + if (var) + g_ServerPort = atoi(var); + + streambuf* cout_streambuf = cout.rdbuf(); + streambuf* cerr_streambuf = cerr.rdbuf(); + + FCGX_Request request; + + FCGX_Init(); + FCGX_InitRequest(&request, 0, 0); + + cout << "Shibboleth initialization complete. Starting request loop." << endl; + while (FCGX_Accept_r(&request) == 0) + { + // Note that the default bufsize (0) will cause the use of iostream + // methods that require positioning (such as peek(), seek(), + // unget() and putback()) to fail (in favour of more efficient IO). + fcgi_streambuf cout_fcgi_streambuf(request.out); + fcgi_streambuf cerr_fcgi_streambuf(request.err); + + cout.rdbuf(&cout_fcgi_streambuf); + cerr.rdbuf(&cerr_fcgi_streambuf); + + try { + xmltooling::NDC ndc("FastCGI shibauthorizer"); + ShibTargetFCGIAuth sta(&request, g_ServerScheme.c_str(), g_ServerName.c_str(), g_ServerPort); + + pair res = sta.getServiceProvider().doAuthentication(sta); + if (res.first) { +#ifdef _DEBUG + cerr << "shib: doAuthentication handled the request" << endl; +#endif + switch(res.second) { + case SHIB_RETURN_OK: + print_ok(sta.m_request_headers); + continue; + + case SHIB_RETURN_KO: + print_ok(sta.m_request_headers); + continue; + + case SHIB_RETURN_DONE: + continue; + + default: + cerr << "shib: doAuthentication returned an unexpected result: " << res.second << endl; + print_error("FastCGI Shibboleth authorizer returned an unexpected result."); + continue; + } + } + + res = sta.getServiceProvider().doExport(sta); + if (res.first) { +#ifdef _DEBUG + cerr << "shib: doExport handled request" << endl; +#endif + switch(res.second) { + case SHIB_RETURN_OK: + print_ok(sta.m_request_headers); + continue; + + case SHIB_RETURN_KO: + print_ok(sta.m_request_headers); + continue; + + case SHIB_RETURN_DONE: + continue; + + default: + cerr << "shib: doExport returned an unexpected result: " << res.second << endl; + print_error("FastCGI Shibboleth authorizer returned an unexpected result."); + continue; + } + } + + res = sta.getServiceProvider().doAuthorization(sta); + if (res.first) { +#ifdef _DEBUG + cerr << "shib: doAuthorization handled request" << endl; +#endif + switch(res.second) { + case SHIB_RETURN_OK: + print_ok(sta.m_request_headers); + continue; + + case SHIB_RETURN_KO: + print_ok(sta.m_request_headers); + continue; + + case SHIB_RETURN_DONE: + continue; + + default: + cerr << "shib: doAuthorization returned an unexpected result: " << res.second << endl; + print_error("FastCGI Shibboleth authorizer returned an unexpected result."); + continue; + } + } + + print_ok(sta.m_request_headers); + + } + catch (exception& e) { + cerr << "shib: FastCGI authorizer caught an exception: " << e.what() << endl; + print_error("FastCGI Shibboleth authorizer caught an exception, check log for details."); + } + + // If the output streambufs had non-zero bufsizes and + // were constructed outside of the accept loop (i.e. + // their destructor won't be called here), they would + // have to be flushed here. + } + cout << "Request loop ended." << endl; + + cout.rdbuf(cout_streambuf); + cerr.rdbuf(cerr_streambuf); + + if (g_Config) + g_Config->term(); + + return 0; +} diff --git a/fastcgi/shibauthorizer.vcproj b/fastcgi/shibauthorizer.vcproj new file mode 100644 index 0000000..c82fe22 --- /dev/null +++ b/fastcgi/shibauthorizer.vcproj @@ -0,0 +1,217 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fastcgi/shibresponder.cpp b/fastcgi/shibresponder.cpp new file mode 100644 index 0000000..4cab35d --- /dev/null +++ b/fastcgi/shibresponder.cpp @@ -0,0 +1,413 @@ +/* + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* shibresponder.cpp - Shibboleth FastCGI Responder/Handler + + Andre Cruz +*/ + +#define SHIBSP_LITE +#include "config_win32.h" + +#define _CRT_NONSTDC_NO_DEPRECATE 1 +#define _CRT_SECURE_NO_DEPRECATE 1 +#define _SCL_SECURE_NO_WARNINGS 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#ifdef HAVE_UNISTD_H +# include +# include +#endif +#include + +using namespace shibsp; +using namespace xmltooling; +using namespace xercesc; +using namespace std; + +static const XMLCh path[] = UNICODE_LITERAL_4(p,a,t,h); +static const XMLCh validate[] = UNICODE_LITERAL_8(v,a,l,i,d,a,t,e); + +typedef enum { + SHIB_RETURN_OK, + SHIB_RETURN_KO, + SHIB_RETURN_DONE +} shib_return_t; + +class ShibTargetFCGI : public AbstractSPRequest +{ + FCGX_Request* m_req; + const char* m_body; + multimap m_headers; + int m_port; + string m_scheme,m_hostname; + +public: + ShibTargetFCGI(FCGX_Request* req, char* post_data, const char* scheme=NULL, const char* hostname=NULL, int port=0) + : m_req(req), m_body(post_data) { + + const char* server_name_str = hostname; + if (!server_name_str || !*server_name_str) + server_name_str = FCGX_GetParam("SERVER_NAME", req->envp); + m_hostname = server_name_str; + + m_port = port; + if (!m_port) { + char* server_port_str = FCGX_GetParam("SERVER_PORT", req->envp); + m_port = strtol(server_port_str, &server_port_str, 10); + if (*server_port_str) { + cerr << "can't parse SERVER_PORT (" << FCGX_GetParam("SERVER_PORT", req->envp) << ")" << endl; + throw exception("Unable to determine server port."); + } + } + + const char* server_scheme_str = scheme; + if (!server_scheme_str || !*server_scheme_str) + server_scheme_str = (m_port == 443 || m_port == 8443) ? "https" : "http"; + m_scheme = server_scheme_str; + } + + ~ShibTargetFCGI() { } + + const char* getScheme() const { + return m_scheme.c_str(); + } + const char* getHostname() const { + return m_hostname.c_str(); + } + int getPort() const { + return m_port; + } + const char* getRequestURI() const { + return FCGX_GetParam("REQUEST_URI", m_req->envp); + } + const char* getMethod() const { + return FCGX_GetParam("REQUEST_METHOD", m_req->envp); + } + string getContentType() const { + const char* s = FCGX_GetParam("CONTENT_TYPE", m_req->envp); + return s ? s : ""; + } + long getContentLength() const { + const char* s = FCGX_GetParam("CONTENT_LENGTH", m_req->envp); + return s ? atol(s) : 0; + } + string getRemoteUser() const { + const char* s = FCGX_GetParam("REMOTE_USER", m_req->envp); + return s ? s : ""; + } + string getRemoteAddr() const { + const char* s = FCGX_GetParam("REMOTE_ADDR", m_req->envp); + return s ? s : ""; + } + void log(SPLogLevel level, const string& msg) const { + AbstractSPRequest::log(level,msg); + if (level >= SPError) + cerr << "shib: " << msg; + } + + string getHeader(const char* name) const { + string hdr("HTTP_"); + for (; *name; ++name) { + if (*name=='-') + hdr += '_'; + else + hdr += toupper(*name); + } + char* s = FCGX_GetParam(hdr.c_str(), m_req->envp); + return s ? s : ""; + } + + void setResponseHeader(const char* name, const char* value) { + // Set for later. + if (value) + m_headers.insert(make_pair(name,value)); + else + m_headers.erase(name); + } + + const char* getQueryString() const { + return FCGX_GetParam("QUERY_STRING", m_req->envp); + } + + const char* getRequestBody() const { + return m_body; + } + + long sendResponse(istream& in, long status) { + string hdr = string("Connection: close\r\n"); + for (multimap::const_iterator i=m_headers.begin(); i!=m_headers.end(); ++i) + hdr += i->first + ": " + i->second + "\r\n"; + + const char* codestr="Status: 200 OK"; + switch (status) { + case XMLTOOLING_HTTP_STATUS_ERROR: codestr="Status: 500 Server Error"; break; + case XMLTOOLING_HTTP_STATUS_FORBIDDEN:codestr="Status: 403 Forbidden"; break; + case XMLTOOLING_HTTP_STATUS_NOTFOUND: codestr="Status: 404 Not Found"; break; + } + cout << codestr << "\r\n" << hdr << "\r\n"; + char buf[1024]; + while (in) { + in.read(buf,1024); + cout.write(buf, in.gcount()); + } + return SHIB_RETURN_DONE; + } + + long sendRedirect(const char* url) { + string hdr=string("Status: 302 Please Wait\r\nLocation: ") + url + "\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 40\r\n" + "Expires: 01-Jan-1997 12:00:00 GMT\r\n" + "Cache-Control: private,no-store,no-cache\r\n"; + for (multimap::const_iterator i=m_headers.begin(); i!=m_headers.end(); ++i) + hdr += i->first + ": " + i->second + "\r\n"; + hdr += "\r\n"; + + cout << hdr << "Redirecting..."; + return SHIB_RETURN_DONE; + } + + long returnDecline() { + return SHIB_RETURN_KO; + } + long returnOK() { + return SHIB_RETURN_OK; + } + + const vector& getClientCertificates() const { + static vector g_NoCerts; + return g_NoCerts; + } + + // Not used in the extension. + + virtual void clearHeader(const char* rawname, const char* cginame) { + throw exception("clearHeader not implemented by FastCGI responder."); + } + + virtual void setHeader(const char* name, const char* value) { + throw exception("setHeader not implemented by FastCGI responder."); + } + + virtual void setRemoteUser(const char* user) { + throw exception("setRemoteUser not implemented by FastCGI responder."); + } +}; + +// Maximum number of bytes allowed to be read from stdin +static const unsigned long STDIN_MAX = 1000000; + +static long gstdin(FCGX_Request* request, char** content) +{ + char* clenstr = FCGX_GetParam("CONTENT_LENGTH", request->envp); + unsigned long clen = STDIN_MAX; + + if (clenstr) { + clen = strtol(clenstr, &clenstr, 10); + if (*clenstr) { + cerr << "can't parse CONTENT_LENGTH (" << FCGX_GetParam("CONTENT_LENGTH", request->envp) << ")" << endl; + clen = STDIN_MAX; + } + + // *always* put a cap on the amount of data that will be read + if (clen > STDIN_MAX) + clen = STDIN_MAX; + + *content = new char[clen]; + + cin.read(*content, clen); + clen = cin.gcount(); + } + else { + // *never* read stdin when CONTENT_LENGTH is missing or unparsable + *content = 0; + clen = 0; + } + + // Chew up any remaining stdin - this shouldn't be necessary + // but is because mod_fastcgi doesn't handle it correctly. + + // ignore() doesn't set the eof bit in some versions of glibc++ + // so use gcount() instead of eof()... + do cin.ignore(1024); while (cin.gcount() == 1024); + + return clen; +} + +static void print_ok() { + cout << "Status: 200 OK" << "\r\n\r\n"; +} + +static void print_error(const char* msg) { + cout << "Status: 500 Server Error" << "\r\n\r\n" << msg; +} + +int main(void) +{ + const char* schemadir=getenv("SHIBSP_SCHEMAS"); + if (!schemadir) + schemadir=SHIBSP_SCHEMAS; + const char* config=getenv("SHIBSP_CONFIG"); + if (!config) + config=SHIBSP_CONFIG; + + cerr << "SHIBSP_CONFIG = " << config << endl + << "SHIBSP_SCHEMAS = " << schemadir << endl; + + SPConfig* g_Config=&SPConfig::getConfig(); + g_Config->setFeatures( + SPConfig::Listener | + SPConfig::Caching | + SPConfig::RequestMapping | + SPConfig::InProcess | + SPConfig::Logging | + SPConfig::Handlers + ); + if (!g_Config->init(schemadir)) { + cerr << "failed to initialize Shibboleth libraries" << endl; + exit(1); + } + + try { + DOMDocument* dummydoc=XMLToolingConfig::getConfig().getParser().newDocument(); + XercesJanitor 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(); + } + catch (exception& ex) { + g_Config->term(); + cerr << "exception while initializing Shibboleth configuration: " << ex.what() << endl; + exit(1); + } + + string g_ServerScheme; + string g_ServerName; + int g_ServerPort=0; + + // Load "authoritative" URL fields. + char* var = getenv("SHIBSP_SERVER_NAME"); + if (var) + g_ServerName = var; + var = getenv("SHIBSP_SERVER_SCHEME"); + if (var) + g_ServerScheme = var; + var = getenv("SHIBSP_SERVER_PORT"); + if (var) + g_ServerPort = atoi(var); + + streambuf* cin_streambuf = cin.rdbuf(); + streambuf* cout_streambuf = cout.rdbuf(); + streambuf* cerr_streambuf = cerr.rdbuf(); + + FCGX_Request request; + + FCGX_Init(); + FCGX_InitRequest(&request, 0, 0); + + cout << "Shibboleth initialization complete. Starting request loop." << endl; + while (FCGX_Accept_r(&request) == 0) { + // Note that the default bufsize (0) will cause the use of iostream + // methods that require positioning (such as peek(), seek(), + // unget() and putback()) to fail (in favour of more efficient IO). + fcgi_streambuf cin_fcgi_streambuf(request.in); + fcgi_streambuf cout_fcgi_streambuf(request.out); + fcgi_streambuf cerr_fcgi_streambuf(request.err); + + cin.rdbuf(&cin_fcgi_streambuf); + cout.rdbuf(&cout_fcgi_streambuf); + cerr.rdbuf(&cerr_fcgi_streambuf); + + // Although FastCGI supports writing before reading, + // many http clients (browsers) don't support it (so + // the connection deadlocks until a timeout expires!). + char* content; + gstdin(&request, &content); + + try { + xmltooling::NDC ndc("FastCGI shibresponder"); + ShibTargetFCGI stf(&request, content, g_ServerScheme.c_str(), g_ServerName.c_str(), g_ServerPort); + + pair res = stf.getServiceProvider().doHandler(stf); + if (res.first) { +#ifdef _DEBUG + cerr << "shib: doHandler handled the request" << endl; +#endif + switch(res.second) { + case SHIB_RETURN_OK: + print_ok(); + break; + + case SHIB_RETURN_KO: + cerr << "shib: doHandler failed to handle the request" << endl; + print_error("FastCGI Shibboleth responder should only be used for Shibboleth protocol requests."); + break; + + case SHIB_RETURN_DONE: + // response already handled + break; + + default: + cerr << "shib: doHandler returned an unexpected result: " << res.second << endl; + print_error("FastCGI Shibboleth responder returned an unexpected result."); + break; + } + } + else { + cerr << "shib: doHandler failed to handle request." << endl; + print_error("FastCGI Shibboleth responder failed to process request."); + } + + } + catch (exception& e) { + cerr << "shib: FastCGI responder caught an exception: " << e.what() << endl; + print_error("FastCGI Shibboleth responder caught an exception, check log for details."); + } + + delete[] content; + + // If the output streambufs had non-zero bufsizes and + // were constructed outside of the accept loop (i.e. + // their destructor won't be called here), they would + // have to be flushed here. + } + + cout << "Request loop ended." << endl; + + cin.rdbuf(cin_streambuf); + cout.rdbuf(cout_streambuf); + cerr.rdbuf(cerr_streambuf); + + if (g_Config) + g_Config->term(); + + return 0; +} diff --git a/fastcgi/shibresponder.vcproj b/fastcgi/shibresponder.vcproj new file mode 100644 index 0000000..cb50d89 --- /dev/null +++ b/fastcgi/shibresponder.vcproj @@ -0,0 +1,217 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/isapi_shib/isapi_shib.vcproj b/isapi_shib/isapi_shib.vcproj index 1908d9b..216a23c 100644 --- a/isapi_shib/isapi_shib.vcproj +++ b/isapi_shib/isapi_shib.vcproj @@ -53,7 +53,6 @@ StringPooling="true" RuntimeLibrary="2" EnableFunctionLevelLinking="true" - RuntimeTypeInfo="true" BrowseInformation="1" WarningLevel="3" SuppressStartupBanner="true" @@ -145,7 +144,6 @@ PreprocessorDefinitions="_WINDOWS;WIN32;_DEBUG;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0400" BasicRuntimeChecks="3" RuntimeLibrary="3" - RuntimeTypeInfo="true" BrowseInformation="1" WarningLevel="3" SuppressStartupBanner="true" diff --git a/msi/scripts/shib_edit_config_files.vbs b/msi/scripts/shib_edit_config_files.vbs index 8ac6204..9e07d66 100644 --- a/msi/scripts/shib_edit_config_files.vbs +++ b/msi/scripts/shib_edit_config_files.vbs @@ -93,7 +93,7 @@ if (Err = 0) then ConfigFile = DistDir & "shibboleth2.xml.in" ReplaceInFile ConfigFile, "@-PKGXMLDIR-@", ConvertedDir & "/share/xml/shibboleth" ReplaceInFile ConfigFile, "@-PKGSYSCONFDIR-@", ConvertedDir & "/etc/shibboleth" - ReplaceInFile ConfigFile, "@-LIBEXECDIR-@", ConvertedDir & "/libexec" + ReplaceInFile ConfigFile, "@-PKGLIBDIR-@", ConvertedDir & "/lib/shibboleth" ReplaceInFile ConfigFile, "@-LOGDIR-@", ConvertedDir & "/var/log/shibboleth" ReplaceInFile ConfigFile, "@-PREFIX-@", ConvertedDir ReplaceInFile ConfigFile, " ", "" @@ -131,7 +131,7 @@ if (Err = 0) then ReplaceInFile ConfigFile, "catalog.xml:", "catalog.xml;" ReplaceInFile ConfigFile, "@-PKGDOCDIR-@", ConvertedDir & "/share/doc/shibboleth" ReplaceInFile ConfigFile, "@-PKGSYSCONFDIR-@", ConvertedDir & "/etc/shibboleth" - ReplaceInFile ConfigFile, "@-LIBEXECDIR-@", ConvertedDir & "/libexec" + ReplaceInFile ConfigFile, "@-PKGLIBDIR-@", ConvertedDir & "/lib/shibboleth" If (NOT FileSystemObj.FileExists(ConfigDir & "apache.config")) then FileSystemObj.CopyFile ConfigFile, ConfigDir & "apache.config", false End If @@ -145,7 +145,7 @@ if (Err = 0) then ReplaceInFile ConfigFile, "catalog.xml:", "catalog.xml;" ReplaceInFile ConfigFile, "@-PKGDOCDIR-@", ConvertedDir & "/share/doc/shibboleth" ReplaceInFile ConfigFile, "@-PKGSYSCONFDIR-@", ConvertedDir & "/etc/shibboleth" - ReplaceInFile ConfigFile, "@-LIBEXECDIR-@", ConvertedDir & "/libexec" + ReplaceInFile ConfigFile, "@-PKGLIBDIR-@", ConvertedDir & "/lib/shibboleth" If (NOT FileSystemObj.FileExists(ConfigDir & "apache2.config")) then FileSystemObj.CopyFile ConfigFile, ConfigDir & "apache2.config", false End If @@ -159,7 +159,7 @@ if (Err = 0) then ReplaceInFile ConfigFile, "catalog.xml:", "catalog.xml;" ReplaceInFile ConfigFile, "@-PKGDOCDIR-@", ConvertedDir & "/share/doc/shibboleth" ReplaceInFile ConfigFile, "@-PKGSYSCONFDIR-@", ConvertedDir & "/etc/shibboleth" - ReplaceInFile ConfigFile, "@-LIBEXECDIR-@", ConvertedDir & "/libexec" + ReplaceInFile ConfigFile, "@-PKGLIBDIR-@", ConvertedDir & "/lib/shibboleth" If (NOT FileSystemObj.FileExists(ConfigDir & "apache22.config")) then FileSystemObj.CopyFile ConfigFile, ConfigDir & "apache22.config", false End If diff --git a/nsapi_shib/Makefile.am b/nsapi_shib/Makefile.am index 8362f1f..50be4cb 100644 --- a/nsapi_shib/Makefile.am +++ b/nsapi_shib/Makefile.am @@ -1,7 +1,7 @@ AUTOMAKE_OPTIONS = foreign if BUILD_NSAPI -nsapi_shibdir = $(libexecdir) +nsapi_shibdir = $(libdir)/@PACKAGE@ nsapi_shib_LTLIBRARIES = nsapi_shib.la nsapi_shib_la_SOURCES = nsapi_shib.cpp nsapi_shib_la_CXXFLAGS = $(NSAPI_INCLUDE) @@ -15,4 +15,3 @@ install-exec-hook: endif EXTRA_DIST = nsapi_shib.vcproj resource.h nsapi_shib.rc nsapi_shib.cpp - diff --git a/nsapi_shib/nsapi_shib.vcproj b/nsapi_shib/nsapi_shib.vcproj index 7701483..8251b79 100644 --- a/nsapi_shib/nsapi_shib.vcproj +++ b/nsapi_shib/nsapi_shib.vcproj @@ -53,7 +53,6 @@ StringPooling="true" RuntimeLibrary="2" EnableFunctionLevelLinking="true" - RuntimeTypeInfo="true" WarningLevel="3" SuppressStartupBanner="true" Detect64BitPortabilityProblems="true" @@ -143,7 +142,6 @@ PreprocessorDefinitions="_WINDOWS;WIN32;_DEBUG" BasicRuntimeChecks="3" RuntimeLibrary="3" - RuntimeTypeInfo="true" BrowseInformation="1" WarningLevel="3" SuppressStartupBanner="true" diff --git a/odbc-store/Makefile.am b/odbc-store/Makefile.am index f6c9ebc..c18fe5b 100644 --- a/odbc-store/Makefile.am +++ b/odbc-store/Makefile.am @@ -1,6 +1,6 @@ AUTOMAKE_OPTIONS = foreign -plugindir = $(libexecdir) +plugindir = $(libdir)/@PACKAGE@ plugin_LTLIBRARIES = odbc-store.la AM_CFLAGS = $(ODBC_CFLAGS) -- 2.1.4