From: cantor Date: Thu, 18 Mar 2004 19:04:27 +0000 (+0000) Subject: Modules for new library API, merged shibrm code into mod_shire X-Git-Tag: 2.4~2030 X-Git-Url: http://www.project-moonshot.org/gitweb/?a=commitdiff_plain;h=78680c2f9eee1e11621c1fde2d17eaba88329d78;p=shibboleth%2Fsp.git Modules for new library API, merged shibrm code into mod_shire git-svn-id: https://svn.middleware.georgetown.edu/cpp-sp/trunk@848 cb58f699-b61c-0410-a6fe-9272a202ed29 --- diff --git a/apache-2.0/Makefile.am b/apache-2.0/Makefile.am index bc0fed3..0210da7 100644 --- a/apache-2.0/Makefile.am +++ b/apache-2.0/Makefile.am @@ -9,14 +9,13 @@ endif modshibdir = $(libexecdir) modshib_LTLIBRARIES = mod_shib.la -mod_shib_la_SOURCES = mod_shib.cpp cgiparse.cpp -noinst_HEADERS = cgiparse.h +mod_shib_la_SOURCES = mod_shib.cpp AM_CXXFLAGS = $(APXS2_CFLAGS) -I$(APXS2_INCLUDE) $(RPC_CFLAGS) mod_shib_la_LIBADD = $(top_builddir)/shib/libshib.la $(top_builddir)/shib-target/libshib-target.la -mod_shib_la_LDFLAGS = -module -avoid-version -lapreq +mod_shib_la_LDFLAGS = -module -avoid-version if DO_APXS2_INSTALL install-exec-local: diff --git a/apache-2.0/cgiparse.cpp b/apache-2.0/cgiparse.cpp deleted file mode 100644 index 2086d92..0000000 --- a/apache-2.0/cgiparse.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/* - * The Shibboleth License, Version 1. - * Copyright (c) 2002 - * University Corporation for Advanced Internet Development, Inc. - * All rights reserved - * - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution, if any, must include - * the following acknowledgment: "This product includes software developed by - * the University Corporation for Advanced Internet Development - * Internet2 Project. Alternately, this acknowledegement - * may appear in the software itself, if and wherever such third-party - * acknowledgments normally appear. - * - * Neither the name of Shibboleth nor the names of its contributors, nor - * Internet2, nor the University Corporation for Advanced Internet Development, - * Inc., nor UCAID may be used to endorse or promote products derived from this - * software without specific prior written permission. For written permission, - * please contact shibboleth@shibboleth.org - * - * Products derived from this software may not be called Shibboleth, Internet2, - * UCAID, or the University Corporation for Advanced Internet Development, nor - * may Shibboleth appear in their name, without prior written permission of the - * University Corporation for Advanced Internet Development. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK - * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE. - * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY - * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* cgiparse.cpp - URL-encoded parameter parsing - - Scott Cantor - 7/6/03 - - Derek Atkins - 2004-02-25 -*/ - -#include -#include -#include - -#include - -#include "cgiparse.h" - -using namespace shibtarget; -using namespace std; - -class CgiParseImpl : CgiParse{ -public: - ~CgiParseImpl() {}; - CgiParseImpl(string& cgi); - const char * get_value(const string& name) const; - -private: - map kvp_map; -}; - - -namespace { - -/* Parsing routines modified from NCSA source. */ -char *makeword(char *line, char stop) -{ - int x = 0,y; - char *word = (char *) malloc(sizeof(char) * (strlen(line) + 1)); - - for(x=0;((line[x]) && (line[x] != stop));x++) - word[x] = line[x]; - - word[x] = '\0'; - if(line[x]) - ++x; - y=0; - - while(line[x]) - line[y++] = line[x++]; - line[y] = '\0'; - return word; -} - -char *fmakeword(char stop, int *cl, const char** ppch) -{ - int wsize; - char *word; - int ll; - - wsize = 1024; - ll=0; - word = (char *) malloc(sizeof(char) * (wsize + 1)); - - while(1) - { - word[ll] = *((*ppch)++); - if(ll==wsize-1) - { - word[ll+1] = '\0'; - wsize+=1024; - word = (char *)realloc(word,sizeof(char)*(wsize+1)); - } - --(*cl); - if((word[ll] == stop) || word[ll] == EOF || (!(*cl))) - { - if(word[ll] != stop) - ll++; - word[ll] = '\0'; - return word; - } - ++ll; - } -} - -char x2c(char *what) -{ - register char digit; - - digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0')); - digit *= 16; - digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0')); - return(digit); -} - -void unescape_url(char *url) -{ - register int x,y; - - for(x=0,y=0;url[y];++x,++y) - { - if((url[x] = url[y]) == '%') - { - url[x] = x2c(&url[y+1]); - y+=2; - } - } - url[x] = '\0'; -} - -void plustospace(char *str) -{ - register int x; - - for(x=0;str[x];x++) - if(str[x] == '+') str[x] = ' '; -} - -}; // end of private namespace - -CgiParseImpl::CgiParseImpl(string& cgi) -{ - int cl; - const char* pch; - -#if 0 - /* Verify method and content type. */ - if(!stricmp(lpECB->lpszMethod,"POST")) - { - if (stricmp(lpECB->lpszContentType,"application/x-www-form-urlencoded")) - return NULL; - pch=lpECB->lpbData; - cl=lpECB->cbAvailable; - } - else if (!stricmp(lpECB->lpszMethod,"GET")) - { - pch=lpECB->lpszQueryString; - cl=strlen(pch); - } - else - return NULL; -#else - pch = cgi.c_str(); - cl = strlen(pch); -#endif - - while (cl && pch) - { - char *name; - char *value; - value=fmakeword('&',&cl,&pch); - plustospace(value); - unescape_url(value); - name=makeword(value,'='); - - kvp_map[name]=value; - free(name); - free(value); - } -} - - -const char * -CgiParseImpl::get_value(const string& name) const -{ - map::const_iterator i=kvp_map.find(name); - if (i==kvp_map.end()) - return NULL; - - return i->second.c_str(); -} - -CgiParse* -CgiParse::ParseCGI(string& input) -{ - CgiParseImpl* res = new CgiParseImpl(input); - return (CgiParse*) res; -} diff --git a/apache-2.0/cgiparse.h b/apache-2.0/cgiparse.h deleted file mode 100644 index 689c1ce..0000000 --- a/apache-2.0/cgiparse.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * The Shibboleth License, Version 1. - * Copyright (c) 2002 - * University Corporation for Advanced Internet Development, Inc. - * All rights reserved - * - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution, if any, must include - * the following acknowledgment: "This product includes software developed by - * the University Corporation for Advanced Internet Development - * Internet2 Project. Alternately, this acknowledegement - * may appear in the software itself, if and wherever such third-party - * acknowledgments normally appear. - * - * Neither the name of Shibboleth nor the names of its contributors, nor - * Internet2, nor the University Corporation for Advanced Internet Development, - * Inc., nor UCAID may be used to endorse or promote products derived from this - * software without specific prior written permission. For written permission, - * please contact shibboleth@shibboleth.org - * - * Products derived from this software may not be called Shibboleth, Internet2, - * UCAID, or the University Corporation for Advanced Internet Development, nor - * may Shibboleth appear in their name, without prior written permission of the - * University Corporation for Advanced Internet Development. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK - * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE. - * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY - * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* cgiparse.h - URL-encoded parameter parsing - - Scott Cantor - 7/6/03 - - Derek Atkins - 2004-02-25 -*/ - -#ifndef __CGIPARSE__ -#define __CGIPARSE__ - -#include - -namespace shibtarget { - - class CgiParse { - public: - virtual ~CgiParse() { }; - virtual const char * get_value(const std::string& name) const = 0; - - const char * get_value(const char* name) const { - std::string val(name ? name : ""); - return get_value(val); - }; - - static CgiParse* ParseCGI(std::string& input); - }; -} - -#endif /* __CGIPARSE__ */ diff --git a/apache-2.0/mod_shib.cpp b/apache-2.0/mod_shib.cpp index d46df03..3cf37e9 100644 --- a/apache-2.0/mod_shib.cpp +++ b/apache-2.0/mod_shib.cpp @@ -11,6 +11,7 @@ #include #include #include +#include // Apache specific header files #include @@ -18,26 +19,20 @@ #include #include #include -#include #include #define CORE_PRIVATE #include #include #include -#include - #include #include -#include -// For POST processing from Apache -//-- do we still need this? #undef _XOPEN_SOURCE // bombs on solaris -#include - -#include "cgiparse.h" +//#include +#ifdef HAVE_UNISTD_H #include // for getpid() +#endif using namespace std; using namespace saml; @@ -45,10 +40,14 @@ using namespace shibboleth; using namespace shibtarget; extern "C" AP_MODULE_DECLARE_DATA module mod_shib; +int shib_handler(request_rec* r, const IApplication* application, const IPropertySet* sessionProps, SHIRE& shire); namespace { char* g_szSHIBConfig = NULL; + char* g_szSchemaDir = NULL; ShibTargetConfig* g_Config = NULL; + bool g_bApacheConf = false; + static const char* g_UserDataKey = "_shib_check_user_"; } // per-dir module configuration structure @@ -56,30 +55,23 @@ struct shib_dir_config { // RM Configuration char* szAuthGrpFile; // Auth GroupFile name - int bExportAssertion; // export SAML assertion to the environment? int bRequireAll; // all require directives must match, otherwise OR logic - int bDisableRM; // disable the RM functionality? // SHIRE Configuration int bBasicHijack; // activate for AuthType Basic? - int bSSLOnly; // only over SSL? - SHIREConfig config; // SHIB Configuration - RMConfig rm_config; // RM Configuration + int bRequireSession; // require a session? + int bExportAssertion; // export SAML assertion to the environment? }; // creates per-directory config structure extern "C" void* create_shib_dir_config (apr_pool_t* p, char* d) { shib_dir_config* dc=(shib_dir_config*)apr_pcalloc(p,sizeof(shib_dir_config)); - dc->szAuthGrpFile = NULL; + dc->bBasicHijack = -1; + dc->bRequireSession = -1; dc->bExportAssertion = -1; dc->bRequireAll = -1; - dc->bDisableRM = -1; - - dc->bBasicHijack = -1; - dc->bSSLOnly = -1; - dc->config.lifetime = -1; - dc->config.timeout = -1; + dc->szAuthGrpFile = NULL; return dc; } @@ -97,20 +89,11 @@ extern "C" void* merge_shib_dir_config (apr_pool_t* p, void* base, void* sub) else dc->szAuthGrpFile=NULL; - dc->bExportAssertion=((child->bExportAssertion==-1) ? - parent->bExportAssertion : child->bExportAssertion); - dc->bRequireAll=((child->bRequireAll==-1) ? - parent->bRequireAll : child->bRequireAll); - dc->bDisableRM=((child->bDisableRM==-1) ? - parent->bDisableRM : child->bDisableRM); - - dc->bBasicHijack=((child->bBasicHijack==-1) ? - parent->bBasicHijack : child->bBasicHijack); - dc->bSSLOnly=((child->bSSLOnly==-1) ? parent->bSSLOnly : child->bSSLOnly); - dc->config.lifetime=((child->config.lifetime==-1) ? - parent->config.lifetime : child->config.lifetime); - dc->config.timeout=((child->config.timeout==-1) ? - parent->config.timeout : child->config.timeout); + dc->bBasicHijack=((child->bBasicHijack==-1) ? parent->bBasicHijack : child->bBasicHijack); + dc->bRequireSession=((child->bRequireSession==-1) ? parent->bRequireSession : child->bRequireSession); + dc->bExportAssertion=((child->bExportAssertion==-1) ? parent->bExportAssertion : child->bExportAssertion); + dc->bRequireAll=((child->bRequireAll==-1) ? parent->bRequireAll : child->bRequireAll); + return dc; } @@ -122,182 +105,30 @@ extern "C" const char* ap_set_global_string_slot(cmd_parms* parms, void*, return NULL; } -// some shortcuts for directory config slots -extern "C" const char* set_lifetime(cmd_parms* parms, shib_dir_config* dc, - const char* arg) -{ - dc->config.lifetime=atoi(arg); - return NULL; -} - -extern "C" const char* set_timeout(cmd_parms* parms, shib_dir_config* dc, - const char* arg) -{ - dc->config.timeout=atoi(arg); - return NULL; -} - typedef const char* (*config_fn_t)(void); -static char* url_encode(request_rec* r, const char* s) +static int shib_error_page(request_rec* r, const IApplication* app, const char* page, ShibMLP& mlp) { - int len=strlen(s); - char* ret=(char*)apr_palloc(r->pool,sizeof(char)*3*len+1); - - // apreq_decode takes a string and url-encodes it. Don't ask why - // the name is backwards. - apreq_decode(ret, s, len); - return ret; -} - -static const char* get_shire_location(request_rec* r, const char* target, - const char* application_id) -{ - ShibINI& ini = g_Config->getINI(); - string shire_location; - bool shire_ssl_only = false; - - // Determine if this is supposed to be ssl-only (default == false) - if (ini.get_tag (application_id, "shireSSLOnly", true, &shire_location)) - shire_ssl_only = ShibINI::boolean(shire_location); - - // Grab the specified shire-location from the config file - if (! ini.get_tag (application_id, "shireURL", true, &shire_location)) { - ap_log_rerror(APLOG_MARK,APLOG_CRIT,0,r, - "shire_get_location() no shireURL configuration for %s", - application_id); - return NULL; - } - - // - // The "shireURL" can be one of three formats: - // - // 1) a full URI: http://host/foo/bar - // 2) a partial URI: http:///foo/bar - // 3) a relative path: /foo/bar - // - // # Protocol Host Path - // 1 shire shire shire - // 2 shire target shire - // 3 target target shire - // - // note: if shire_ssl_only is true, make sure the protocol is https - // - - const char* shire = shire_location.c_str(); - const char* path = NULL; - - // Decide whether to use the shire or the target for the "protocol" - const char* prot; - if (*shire != '/') { - prot = shire; - } else { - prot = target; - path = shire; - } - - // ap_log_rerror(APLOG_MARK,APLOG_DEBUG,0,r, - // "get_shire_location: prot=%s, path=%s", prot, - // path ? path : "(null)"); - - // break apart the "protocol" string into protocol, host, and "the rest" - const char* colon=strchr(prot,':'); - colon += 3; - const char* slash=strchr(colon,'/'); - if (!path) - path = slash; - - // Compute the actual protocol - const char* proto; - if (shire_ssl_only) - proto = "https://"; - else - proto = apr_pstrndup(r->pool, prot, colon-prot); - - // create the "host" from either the colon/slash or from the target string - // If prot == shire then we're in either #1 or #2, else #3. - // If slash == colon then we're in #2 - if (prot != shire || slash == colon) { - colon = strchr(target, ':'); - colon += 3; // Get past the :// - slash = strchr(colon, '/'); - } - const char *host = apr_pstrndup(r->pool, colon, slash-colon); - - // Build the shire URL - return apr_pstrcat(r->pool, proto, host, path, NULL); -} - -static int shib_error_page(request_rec* r, const char* filename, ShibMLP& mlp) -{ - ifstream infile (filename); - if (!infile) { - ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r, - "shib_error_page() cannot open %s", filename); - return HTTP_INTERNAL_SERVER_ERROR; - } - - string res = mlp.run(infile); - r->content_type = apr_psprintf(r->pool, "text/html"); - ap_rprintf(r, res.c_str()); - return DONE; -} - -static const char* get_application_id(request_rec* r) -{ - ApplicationMapper mapper; - return apr_pstrdup(r->pool, - mapper->getApplicationFromParsedURL( - ap_http_method(r), ap_get_server_name(r), - ap_get_server_port(r), r->unparsed_uri - ) - ); -} - -static apr_table_t* groups_for_user(request_rec* r, const char* user, char* grpfile) -{ - ap_configfile_t* f; - apr_table_t* grps=apr_table_make(r->pool,15); - char l[MAX_STRING_LEN]; - const char *group_name, *ll, *w; - - if (ap_pcfg_openfile(&f,r->pool,grpfile) != APR_SUCCESS) - { - ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r, - "groups_for_user() could not open group file: %s\n", grpfile); - return NULL; - } - - apr_pool_t* sp; - if (apr_pool_create(&sp,r->pool) != APR_SUCCESS) - { - ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r, - "groups_for_user() could not create a subpool"); - return NULL; + const IPropertySet* props=app->getPropertySet("Errors"); + if (props) { + pair p=props->getString(page); + if (p.first) { + ifstream infile(p.second); + if (!infile.fail()) { + const char* res = mlp.run(infile); + if (res) { + r->content_type = apr_psprintf(r->pool, "text/html"); + //ap_send_http_header(r); + ap_rprintf(r, res); + return DONE; + } + } + } } - while (!(ap_cfg_getline(l,MAX_STRING_LEN,f))) - { - if ((*l=='#') || (!*l)) - continue; - ll = l; - apr_pool_clear(sp); - - group_name=ap_getword(sp,&ll,':'); - - while (*ll) - { - w=ap_getword_conf(sp,&ll); - if (!strcmp(w,user)) - { - apr_table_setn(grps,apr_pstrdup(r->pool,group_name),"in"); - break; - } - } - } - ap_cfg_closefile(f); - apr_pool_destroy(sp); - return grps; + ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r, + "shire_error_page() could not process shire error template for application %s",app->getId()); + return HTTP_INTERNAL_SERVER_ERROR; } extern "C" int shib_check_user(request_rec* r) @@ -305,30 +136,50 @@ extern "C" int shib_check_user(request_rec* r) ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r,"shib_check_user: ENTER"); shib_dir_config* dc=(shib_dir_config*)ap_get_module_config(r->per_dir_config,&mod_shib); + ostringstream threadid; + threadid << "[" << getpid() << "] shib" << '\0'; + saml::NDC ndc(threadid.str().c_str()); + // This will always be normalized, because Apache uses ap_get_server_name in this API call. const char* targeturl=ap_construct_url(r->pool,r->unparsed_uri,r); - // Map request to application ID, which is the key for config lookup. - const char* application_id=get_application_id(r); + // We lock the configuration system for the duration. + IConfig* conf=g_Config->getINI(); + Locker locker(conf); - // Get unescaped location of this application's assertion consumer service. - const char* unescaped_shire = get_shire_location(r, targeturl, application_id); + // Map request to application and content settings. + IRequestMapper* mapper=conf->getRequestMapper(); + Locker locker2(mapper); + IRequestMapper::Settings settings=mapper->getSettingsFromParsedURL( + ap_http_method(r), ap_get_server_name(r), ap_get_server_port(r), r->unparsed_uri + ); + pair 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) { + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,0,r, + "shib_check_user: unable to map request to application session settings, check configuration"); + return HTTP_INTERNAL_SERVER_ERROR; + } + + // Declare SHIRE object for this request. + SHIRE shire(application); - if (strstr(targeturl,unescaped_shire)) { - ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,0,r, - "shib_check_user: REQUEST FOR SHIRE! Maybe you did not configure the SHIRE Handler?"); - return HTTP_INTERNAL_SERVER_ERROR; + // Get location of this application's assertion consumer service and see if this is it. + if (strstr(targeturl,shire.getShireURL(targeturl))) { + return shib_handler(r,application,sessionProps,shire); } - else { - // Regular access to arbitrary resource...check AuthType - const char *auth_type=ap_auth_type (r); - if (!auth_type) + + // We can short circuit the handler if we run this... + apr_pool_userdata_setn((const void*)42,g_UserDataKey,NULL,r->pool); + + // Regular access to arbitrary resource...check AuthType + const char *auth_type=ap_auth_type(r); + if (!auth_type) return DECLINED; - if (strcasecmp(auth_type,"shibboleth")) - { - if (!strcasecmp(auth_type,"basic") && dc->bBasicHijack==1) - { + if (strcasecmp(auth_type,"shibboleth")) { + if (!strcasecmp(auth_type,"basic") && dc->bBasicHijack==1) { core_dir_config* conf= (core_dir_config*)ap_get_module_config(r->per_dir_config, ap_find_linked_module("http_core.c")); @@ -336,71 +187,35 @@ extern "C" int shib_check_user(request_rec* r) } else return DECLINED; - } - - // set the connection authtype - r->ap_auth_type = "shibboleth"; - - // SSL check. - if (dc->bSSLOnly==1 && strcmp(ap_http_method(r),"https")) - { - ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,0,r, - "shib_check_user() blocked non-SSL access"); - return HTTP_INTERNAL_SERVER_ERROR; - } } - ostringstream threadid; - threadid << "[" << getpid() << "] shib" << '\0'; - saml::NDC ndc(threadid.str().c_str()); - - ShibINI& ini = g_Config->getINI(); - - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shib_check_user() Shib check for %s", targeturl); - - string tag; - bool has_tag = ini.get_tag (application_id, "checkIPAddress", true, &tag); - dc->config.checkIPAddress = (has_tag ? ShibINI::boolean (tag) : false); - - string shib_cookie; - if (! ini.get_tag(application_id, "cookieName", true, &shib_cookie)) { - ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,0,r, - "shib_check_user: no cookieName configuration for %s", - application_id); - return HTTP_INTERNAL_SERVER_ERROR; + pair requireSession = pair(false,false); + if (g_bApacheConf) { + // By default, we will require a session. + if (dc->bRequireSession!=0) + requireSession.second=true; } + else + requireSession = settings.first->getBool("requireSession"); - string wayfLocation; - if (! ini.get_tag(application_id, "wayfURL", true, &wayfLocation)) { - ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,0,r, - "shib_check_user: no wayfURL configuration for %s", - application_id); - return HTTP_INTERNAL_SERVER_ERROR; - } + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r,"shib_check_user: session check for %s",targeturl); - string shireError; - if (! ini.get_tag(application_id, "shireError", true, &shireError)) { - ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,0,r, - "shib_check_user: no shireError configuration for %s", - application_id); - return HTTP_INTERNAL_SERVER_ERROR; + pair shib_cookie=sessionProps->getString("cookieName"); + if (!shib_cookie.first) { + ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,0,r, + "shib_check_user: no cookieName set for %s", application_id.second); + return HTTP_INTERNAL_SERVER_ERROR; } - - SHIRE shire(dc->config, unescaped_shire); // We're in charge, so check for cookie. const char* session_id=NULL; const char* cookies=apr_table_get(r->headers_in,"Cookie"); - if (cookies) - { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shire_check_user() cookies found: %s",cookies); - if (session_id=strstr(cookies,shib_cookie.c_str())) - { + if (cookies) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r,"shib_check_user() cookies found: %s",cookies); + if (session_id=strstr(cookies,shib_cookie.second)) { // Yep, we found a cookie -- pull it out (our session_id) - session_id+=strlen(shib_cookie.c_str()) + 1; /* Skip over the '=' */ + session_id+=strlen(shib_cookie.second) + 1; /* Skip over the '=' */ char* cookiebuf = apr_pstrdup(r->pool,session_id); char* cookieend = strchr(cookiebuf,';'); if (cookieend) @@ -409,334 +224,447 @@ extern "C" int shib_check_user(request_rec* r) } } - if (!session_id || !*session_id) - { - // No cookie. Redirect to WAYF. - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shib_check_user() no cookie found -- redirecting to WAYF"); - char timebuf[16]; - sprintf(timebuf,"%u",time(NULL)); - char* wayf=apr_pstrcat(r->pool,wayfLocation.c_str(), - "?shire=",url_encode(r,unescaped_shire), - "&target=",url_encode(r,targeturl), - "&time=",timebuf, - "&providerId=",application_id, - NULL); - apr_table_setn(r->headers_out,"Location",wayf); + if (!session_id || !*session_id) { + // If no session required, bail now. + if (!requireSession.second) + return DECLINED; + + // No acceptable cookie, and we require a session. Generate an AuthnRequest. + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r,"shib_check_user: no cookie found -- redirecting to WAYF"); + apr_table_setn(r->headers_out,"Location",apr_pstrdup(r->pool,shire.getAuthnRequest(targeturl))); return HTTP_MOVED_TEMPORARILY; } // Make sure this session is still valid RPCError* status = NULL; - ShibMLP markupProcessor; - has_tag = ini.get_tag(application_id, "supportContact", true, &tag); - markupProcessor.insert("supportContact", has_tag ? tag : ""); - has_tag = ini.get_tag(application_id, "logoLocation", true, &tag); - markupProcessor.insert("logoLocation", has_tag ? tag : ""); + ShibMLP markupProcessor(application); markupProcessor.insert("requestURL", targeturl); try { - status = shire.sessionIsValid(session_id, r->connection->remote_ip,application_id); + status = shire.sessionIsValid(session_id, r->connection->remote_ip); } catch (ShibTargetException &e) { ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r,"shib_check_user(): %s", e.what()); - markupProcessor.insert ("errorType", "SHIRE Processing Error"); - markupProcessor.insert ("errorText", e.what()); - markupProcessor.insert ("errorDesc", "An error occurred while processing your request."); - return shib_error_page (r, shireError.c_str(), markupProcessor); + markupProcessor.insert("errorType", "Session Processing Error"); + markupProcessor.insert("errorText", e.what()); + markupProcessor.insert("errorDesc", "An error occurred while processing your request."); + return shib_error_page(r, application, "shire", markupProcessor); } +#ifndef _DEBUG catch (...) { ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r,"shib_check_user(): caught unexpected error"); - markupProcessor.insert ("errorType", "SHIRE Processing Error"); - markupProcessor.insert ("errorText", "Unexpected Exception"); - markupProcessor.insert ("errorDesc", "An error occurred while processing your request."); - return shib_error_page (r, shireError.c_str(), markupProcessor); + markupProcessor.insert("errorType", "Session Processing Error"); + markupProcessor.insert("errorText", "Unexpected Exception"); + markupProcessor.insert("errorDesc", "An error occurred while processing your request."); + return shib_error_page(r, application, "shire", markupProcessor); } +#endif // Check the status if (status->isError()) { ap_log_rerror(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,0,r, - "shib_check_user() session invalid: %s", - status->getText()); - - if (status->isRetryable()) { - // Oops, session is invalid. Redirect to WAYF. - char timebuf[16]; - sprintf(timebuf,"%u",time(NULL)); - char* wayf=apr_pstrcat(r->pool,wayfLocation.c_str(), - "?shire=",url_encode(r,unescaped_shire), - "&target=",url_encode(r,targeturl), - "&time=",timebuf, - "&providerId=",application_id, - NULL); - apr_table_setn(r->headers_out,"Location",wayf); - + "shib_check_user() session invalid: %s", status->getText()); + + // If no session required, bail now. + if (!requireSession.second) + return DECLINED; + else if (status->isRetryable()) { + // Oops, session is invalid. Generate AuthnRequest. + apr_table_setn(r->headers_out,"Location",apr_pstrdup(r->pool,shire.getAuthnRequest(targeturl))); delete status; return HTTP_MOVED_TEMPORARILY; } else { // return the error page to the user - markupProcessor.insert (*status); + markupProcessor.insert(*status); delete status; - return shib_error_page (r, shireError.c_str(), markupProcessor); + return shib_error_page(r, application, "shire", markupProcessor); } } - else { - delete status; - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shib_check_user() success"); - return OK; + + delete status; + // set the authtype + r->ap_auth_type = "shibboleth"; + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r,"shib_check_user(): session successfully verified"); + + // This is code transferred in from the auth check to export the attributes. + // We could even combine the isSessionValid/getAssertions API...? + + RM rm(application); + vector assertions; + SAMLAuthenticationStatement* sso_statement=NULL; + + try { + status = rm.getAssertions(session_id, r->connection->remote_ip, assertions, &sso_statement); + } + catch (ShibTargetException &e) { + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,0,r,"shib_check_user(): %s", e.what()); + markupProcessor.insert("errorType", "Attribute Processing Error"); + markupProcessor.insert("errorText", e.what()); + markupProcessor.insert("errorDesc", "An error occurred while processing your request."); + return shib_error_page(r, application, "rm", markupProcessor); + } +#ifndef _DEBUG + catch (...) { + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,0,r,"shib_check_user(): caught unexpected error"); + markupProcessor.insert("errorType", "Attribute Processing Error"); + markupProcessor.insert("errorText", "Unexpected Exception"); + markupProcessor.insert("errorDesc", "An error occurred while processing your request."); + return shib_error_page(r, application, "rm", markupProcessor); } +#endif - ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,0,r,"shib_check_user() server error"); - return HTTP_INTERNAL_SERVER_ERROR; -} + if (status->isError()) { + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,0,r, + "shire_check_user() getAssertions failed: %s", status->getText()); -extern "C" int shib_shire_handler (request_rec* r) -{ - ostringstream threadid; - threadid << "[" << getpid() << "] shire" << '\0'; - saml::NDC ndc(threadid.str().c_str()); + markupProcessor.insert(*status); + delete status; + return shib_error_page(r, application, "rm", markupProcessor); + } + delete status; - // This will always be normalized, because Apache uses - // ap_get_server_name in this API call. - const char* targeturl=ap_construct_url(r->pool,r->unparsed_uri,r); + // Do we have an access control plugin? + if (settings.second) { + Locker acllock(settings.second); + if (!settings.second->authorized(assertions)) { + for (int k = 0; k < assertions.size(); k++) + delete assertions[k]; + delete sso_statement; + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,0,r,"shib_check_user(): access control provider denied access"); + return shib_error_page(r, application, "access", markupProcessor); + } + } - // Map request to application ID, which is the key for config lookup. - const char* application_id = get_application_id(r); - - // Find out what SHOULD be the SHIRE URL... - const char* unescaped_shire = get_shire_location(r, targeturl, application_id); - - // Make sure we only process the SHIRE posts. - if (!strstr(targeturl,unescaped_shire)) - return DECLINED; - - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shire_post_handler() ENTER"); - - ShibINI& ini = g_Config->getINI(); - ShibMLP markupProcessor; - - string tag; - bool has_tag = ini.get_tag(application_id, "checkIPAddress", true, &tag); - SHIREConfig config; - config.checkIPAddress = (has_tag ? ShibINI::boolean(tag) : false); - - string shib_cookie; - if (! ini.get_tag(application_id, "cookieName", true, &shib_cookie)) { - ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,0,r, - "shire_post_handler: no cookieName configuration for %s", - application_id); - return HTTP_INTERNAL_SERVER_ERROR; - } + // Get the AAP providers, which contain the attribute policy info. + Iterator provs=application->getAAPProviders(); - string wayfLocation; - if (! ini.get_tag(application_id, "wayfURL", true, &wayfLocation)) { - ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,0,r, - "shire_post_handler: no wayfURL configuration for %s", - application_id); - return HTTP_INTERNAL_SERVER_ERROR; - } + // Clear out the list of mapped attributes + while (provs.hasNext()) { + IAAP* aap=provs.next(); + aap->lock(); + try { + Iterator rules=aap->getAttributeRules(); + while (rules.hasNext()) { + const char* header=rules.next()->getHeader(); + if (header) + apr_table_unset(r->headers_in,header); + } + } + catch(...) { + aap->unlock(); + for (int k = 0; k < assertions.size(); k++) + delete assertions[k]; + delete sso_statement; + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,0,r, + "shib_check_user(): caught unexpected error while clearing headers"); + markupProcessor.insert("errorType", "Attribute Processing Error"); + markupProcessor.insert("errorText", "Unexpected Exception"); + markupProcessor.insert("errorDesc", "An error occurred while processing your request."); + return shib_error_page(r, application, "rm", markupProcessor); + } + aap->unlock(); + } + provs.reset(); + + // Maybe export the first assertion. + apr_table_unset(r->headers_in,"Shib-Attributes"); + pair exp=pair(false,false); + if (g_bApacheConf && dc->bExportAssertion==1) + exp.second=exp.first=true; + else if (!g_bApacheConf) + exp=settings.first->getBool("exportAssertion"); + if (exp.first && exp.second && assertions.size()) { + string assertion; + RM::serialize(*(assertions[0]), assertion); + apr_table_set(r->headers_in,"Shib-Attributes", assertion.c_str()); + } - string shireError; - if (! ini.get_tag(application_id, "shireError", true, &shireError)) { - ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,0,r, - "shire_post_handler: no shireError configuration for %s", - application_id); - return HTTP_INTERNAL_SERVER_ERROR; - } + // Export the SAML AuthnMethod and the origin site name. + apr_table_unset(r->headers_in,"Shib-Origin-Site"); + apr_table_unset(r->headers_in,"Shib-Authentication-Method"); + if (sso_statement) { + auto_ptr_char os(sso_statement->getSubject()->getNameQualifier()); + auto_ptr_char am(sso_statement->getAuthMethod()); + apr_table_set(r->headers_in,"Shib-Origin-Site", os.get()); + apr_table_set(r->headers_in,"Shib-Authentication-Method", am.get()); + } + + apr_table_unset(r->headers_in,"Shib-Application-ID"); + apr_table_set(r->headers_in,"Shib-Application-ID",application_id.second); - has_tag = ini.get_tag(application_id, "supportContact", true, &tag); - markupProcessor.insert("supportContact", has_tag ? tag : ""); - has_tag = ini.get_tag(application_id, "logoLocation", true, &tag); - markupProcessor.insert("logoLocation", has_tag ? tag : ""); - markupProcessor.insert("requestURL", targeturl); - - SHIRE shire(config, unescaped_shire); + // Export the attributes. + Iterator a_iter(assertions); + while (a_iter.hasNext()) { + SAMLAssertion* assert=a_iter.next(); + Iterator statements=assert->getStatements(); + while (statements.hasNext()) { + SAMLAttributeStatement* astate=dynamic_cast(statements.next()); + if (!astate) + continue; + Iterator attrs=astate->getAttributes(); + while (attrs.hasNext()) { + SAMLAttribute* attr=attrs.next(); + + // Are we supposed to export it? + AAP wrapper(provs,attr->getName(),attr->getNamespace()); + if (wrapper.fail()) + continue; + + Iterator vals=attr->getSingleByteValues(); + if (!strcmp(wrapper->getHeader(),"REMOTE_USER") && vals.hasNext()) + r->user=apr_pstrdup(r->pool,vals.next().c_str()); + else { + int it=0; + char* header = (char*)apr_table_get(r->headers_in, wrapper->getHeader()); + if (header) { + header=apr_pstrdup(r->pool, header); + it++; + } + else + header = apr_pstrdup(r->pool, ""); + for (; vals.hasNext(); it++) { + string value = vals.next(); + for (string::size_type pos = value.find_first_of(";", string::size_type(0)); + pos != string::npos; + pos = value.find_first_of(";", pos)) { + value.insert(pos, "\\"); + pos += 2; + } + header=apr_pstrcat(r->pool, header, (it ? ";" : ""), value.c_str(), NULL); + } + apr_table_setn(r->headers_in, wrapper->getHeader(), header); + } + } + } + } - // Process SHIRE POST + // clean up memory + for (int k = 0; k < assertions.size(); k++) + delete assertions[k]; + delete sso_statement; - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shire_post_handler() Beginning SHIRE POST processing"); - - CgiParse* cgi = NULL; + return OK; +} - try { - string sslonly; - if (!ini.get_tag(application_id, "shireSSLOnly", true, &sslonly)) - ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,0,r, - "shire_post_handler: no shireSSLOnly configuration"); +extern "C" int shib_post_handler(request_rec* r) +{ + // With 2.x, this handler always runs, though last. We check if shib_check_user ran, + // because it will detect a SHIRE request and dispatch it directly. + void* data; + apr_pool_userdata_get(&data,g_UserDataKey,r->pool); + if (data==(const void*)42) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r,"shib_post_handler skipped since check_user ran"); + return DECLINED; + } - // Make sure this is SSL, if it should be - if (ShibINI::boolean(sslonly) && strcmp(ap_http_method(r),"https")) - throw ShibTargetException (SHIBRPC_OK, - "blocked non-SSL access to SHIRE POST processor"); - - // Make sure this is a POST - if (strcasecmp (r->method, "POST")) - throw ShibTargetException (SHIBRPC_OK, - "blocked non-POST to SHIRE POST processor"); - - // Sure sure this POST is an appropriate content type - const char *ct = apr_table_get (r->headers_in, "Content-type"); - if (!ct || strcasecmp (ct, "application/x-www-form-urlencoded")) - throw ShibTargetException (SHIBRPC_OK, - apr_psprintf(r->pool, - "blocked bad content-type to SHIRE POST processor: %s", - (ct ? ct : ""))); - - // Make sure the "bytes sent" is a reasonable number - if (r->bytes_sent > 1024*1024) // 1MB? - throw ShibTargetException (SHIBRPC_OK, - "blocked too-large a post to SHIRE POST processor"); + ostringstream threadid; + threadid << "[" << getpid() << "] shib_post_handler" << '\0'; + saml::NDC ndc(threadid.str().c_str()); - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shire_post_handler() about to run setup_client_block"); + // We lock the configuration system for the duration. + IConfig* conf=g_Config->getINI(); + Locker locker(conf); + + // Map request to application and content settings. + IRequestMapper* mapper=conf->getRequestMapper(); + Locker locker2(mapper); + IRequestMapper::Settings settings=mapper->getSettingsFromParsedURL( + ap_http_method(r), ap_get_server_name(r), ap_get_server_port(r), r->unparsed_uri + ); + pair 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) { + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,0,r, + "shib_post_handler: unable to map request to application session settings, check configuration"); + return HTTP_INTERNAL_SERVER_ERROR; + } + + // Declare SHIRE object for this request. + SHIRE shire(application); + + return shib_handler(r, application, sessionProps, shire); +} - // Read the posted data - if (ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)) - throw ShibTargetException (SHIBRPC_OK, "CGI setup_client_block failed"); +int shib_handler(request_rec* r, const IApplication* application, const IPropertySet* sessionProps, SHIRE& shire) +{ + // Prime the pump... + const char* targeturl = ap_construct_url(r->pool,r->unparsed_uri,r); - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shire_post_handler() about to run should_client_block"); + // Make sure we only process the SHIRE requests. + if (!strstr(targeturl,shire.getShireURL(targeturl))) + return DECLINED; - if (!ap_should_client_block(r)) - throw ShibTargetException (SHIBRPC_OK, "CGI should_client_block failed"); - long length = r->remaining; - if (length > 1024*1024) - throw ShibTargetException (SHIBRPC_OK, "CGI length too long..."); + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r,"shib_handler() running"); - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shire_post_handler() about to read using get_client_block"); - string cgistr = ""; - char buff[BUFSIZ]; - //ap_hard_timeout("[mod_shib] CGI Parser", r); - - memset(buff, 0, sizeof(buff)); - while (ap_get_client_block(r, buff, sizeof(buff)-1) > 0) { - cgistr += buff; - memset(buff, 0, sizeof(buff)); + pair shib_cookie=sessionProps->getString("cookieName"); + pair shib_cookie_props=sessionProps->getString("cookieProps"); + if (!shib_cookie.first) { + ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,0,r, + "shire_handler: no cookieName set for %s", application->getId()); + return HTTP_INTERNAL_SERVER_ERROR; } - //ap_kill_timeout(r); - - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shire_post_handler() about to parse cgi..."); + ShibMLP markupProcessor(application); + markupProcessor.insert("requestURL", targeturl); - cgi = CgiParse::ParseCGI(cgistr); + // Process SHIRE request + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r,"shib_handler() Beginning SHIRE processing"); + + try { + pair shireSSL=sessionProps->getBool("shireSSL"); + + // Make sure this is SSL, if it should be + if ((!shireSSL.first || shireSSL.second) && strcmp(ap_http_method(r),"https")) + throw ShibTargetException(SHIBRPC_OK, "blocked non-SSL access to session creation service"); + + // If this is a GET, we manufacture an AuthnRequest. + if (!strcasecmp(r->method,"GET")) { + const char* areq=r->args ? shire.getLazyAuthnRequest(r->args) : NULL; + if (!areq) + throw ShibTargetException(SHIBRPC_OK, "malformed arguments to request a new session"); + apr_table_setn(r->headers_out, "Location", apr_pstrdup(r->pool,areq)); + return HTTP_MOVED_TEMPORARILY; + } + else if (strcasecmp(r->method,"POST")) { + throw ShibTargetException(SHIBRPC_OK, "blocked non-POST to SHIRE POST processor"); + } - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shire_post_handler() CGI parsed... (%p)", cgi); + // Sure sure this POST is an appropriate content type + const char *ct = apr_table_get(r->headers_in, "Content-type"); + if (!ct || strcasecmp(ct, "application/x-www-form-urlencoded")) + throw ShibTargetException (SHIBRPC_OK, + apr_psprintf(r->pool, "blocked bad content-type to SHIRE POST processor: %s", (ct ? ct : ""))); + + // Read the posted data + if (ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)) + throw ShibTargetException (SHIBRPC_OK, "CGI setup_client_block failed"); + if (!ap_should_client_block(r)) + throw ShibTargetException (SHIBRPC_OK, "CGI should_client_block failed"); + if (r->remaining > 1024*1024) + throw ShibTargetException (SHIBRPC_OK, "CGI length too long..."); + + string cgistr; + char buff[HUGE_STRING_LEN]; + //apr_hard_timeout("[mod_shib] CGI Parser", r); + memset(buff, 0, sizeof(buff)); + while (ap_get_client_block(r, buff, sizeof(buff)-1) > 0) { + cgistr += buff; + memset(buff, 0, sizeof(buff)); + } + //ap_kill_timeout(r); - if (!cgi) - throw ShibTargetException (SHIBRPC_OK, "CgiParse failed"); + // Parse the submission. + pair elements=shire.getFormSubmission(cgistr.c_str()); + + // Make sure the SAML Response parameter exists + if (!elements.first || !*elements.first) + throw ShibTargetException(SHIBRPC_OK, "SHIRE POST failed to find SAMLResponse form element"); - // Make sure the target parameter exists - const char *target = cgi->get_value("TARGET"); + // Make sure the target parameter exists + if (!elements.second || !*elements.second) + throw ShibTargetException(SHIBRPC_OK, "SHIRE POST failed to find TARGET form element"); + + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, + "shib_handler() Processing POST for target: %s", elements.second); - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shire_post_handler() obtained target..."); + // process the post + string cookie; + RPCError* status = shire.sessionCreate(elements.first, r->connection->remote_ip, cookie); - if (!target || *target == '\0') - // invalid post - throw ShibTargetException (SHIBRPC_OK, - "SHIRE POST failed to find TARGET"); + if (status->isError()) { + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,0,r, + "shib_handler() POST process failed (%d): %s", status->getCode(), status->getText()); - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shire_post_handler() obtained target..."); + if (status->isRetryable()) { + ap_log_rerror(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,0,r, + "shib_handler() retryable error, generating new AuthnRequest"); + apr_table_setn(r->headers_out,"Location",apr_pstrdup(r->pool,shire.getAuthnRequest(elements.second))); + return HTTP_MOVED_TEMPORARILY; + } - // Make sure the SAML Response parameter exists - const char *post = cgi->get_value("SAMLResponse"); - if (!post || *post == '\0') - // invalid post - throw ShibTargetException (SHIBRPC_OK, - "SHIRE POST failed to find SAMLResponse"); + // return this error to the user. + markupProcessor.insert(*status); + delete status; + return shib_error_page(r, application, "shire", markupProcessor); + } + delete status; - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shire_post_handler() Processing POST for target: %s", target); + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, + "shib_handler() POST process succeeded. New cookie: %s", cookie.c_str()); + + // We've got a good session, set the cookie... + char* val = apr_psprintf(r->pool,"%s=%s%s",shib_cookie.second,cookie.c_str(), + shib_cookie_props.first ? shib_cookie_props.second : ""); + apr_table_setn(r->err_headers_out, "Set-Cookie", val); + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r,"shib_handler() setting cookie: %s",val); + + // ... and redirect to the target + apr_table_setn(r->headers_out, "Location", apr_pstrdup(r->pool,elements.second)); + return HTTP_MOVED_TEMPORARILY; + } + catch (ShibTargetException &e) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r,"shib_post_handler(): %s", e.what()); + markupProcessor.insert("errorType", "Session Creation Service Error"); + markupProcessor.insert("errorText", e.what()); + markupProcessor.insert("errorDesc", "An error occurred while processing your request."); + return shib_error_page(r, application, "shire", markupProcessor); + } +#ifndef _DEBUG + catch (...) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r,"shib_handler(): unexpected exception"); + markupProcessor.insert("errorType", "Session Creation Service Error"); + markupProcessor.insert("errorText", "Unknown Exception"); + markupProcessor.insert("errorDesc", "An error occurred while processing your request."); + return shib_error_page(r, application, "shire", markupProcessor); + } +#endif - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shire_post_handler() POST contents: %s", post); + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,0,r,"shib_handler() server error"); + return HTTP_INTERNAL_SERVER_ERROR; +} - // process the post - string cookie; - RPCError* status = shire.sessionCreate(post, r->connection->remote_ip, application_id, cookie); +static apr_table_t* groups_for_user(request_rec* r, const char* user, char* grpfile) +{ + ap_configfile_t* f; + apr_table_t* grps=apr_table_make(r->pool,15); + char l[MAX_STRING_LEN]; + const char *group_name, *ll, *w; - if (status->isError()) { - ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,0,r, - "shire_post_handler() POST process failed (%d): %s", - status->getCode(), status->getText()); + if (ap_pcfg_openfile(&f,r->pool,grpfile) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r, + "groups_for_user() could not open group file: %s\n", grpfile); + return NULL; + } - if (status->isRetryable()) { - ap_log_rerror(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,0,r, - "shire_post_handler() Retrying POST by redirecting to WAYF"); - - char timebuf[16]; - sprintf(timebuf,"%u",time(NULL)); - char* wayf=apr_pstrcat(r->pool,wayfLocation.c_str(), - "?shire=",url_encode(r,unescaped_shire), - "&target=",url_encode(r,target), - "&time=",timebuf, - "&providerId=",application_id, - NULL); - apr_table_setn(r->headers_out,"Location",wayf); - delete status; - return HTTP_MOVED_TEMPORARILY; - } - - // return this error to the user. - markupProcessor.insert (*status); - delete status; - return shib_error_page (r, shireError.c_str(), markupProcessor); + apr_pool_t* sp; + if (apr_pool_create(&sp,r->pool) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r, + "groups_for_user() could not create a subpool"); + return NULL; } - delete status; - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shire_post_handler() POST process succeeded. New cookie: %s", - cookie.c_str()); - - // We've got a good session, set the cookie... - char * domain = NULL; - char * new_cookie = apr_psprintf(r->pool, "%s=%s; path=/%s%s", - shib_cookie.c_str(), - cookie.c_str(), - (domain ? "; domain=" : ""), - (domain ? domain : "")); - - apr_table_setn(r->err_headers_out, "Set-Cookie", new_cookie); - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shire_post_handler() Set cookie: %s", new_cookie); - - // ... and redirect to the target - char* redir=apr_pstrcat(r->pool,url_encode(r,target),NULL); - apr_table_setn(r->headers_out, "Location", target); - delete cgi; - return HTTP_MOVED_TEMPORARILY; - - } catch (ShibTargetException &e) { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shire_post_handler(): %s", e.what()); - - markupProcessor.insert ("errorType", "SHIRE Processing Error"); - markupProcessor.insert ("errorText", e.what()); - markupProcessor.insert ("errorDesc", "An error occurred while processing your request."); - if (cgi) delete cgi; - return shib_error_page (r, shireError.c_str(), markupProcessor); - } - catch (...) { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r,"shire_post_handler(): unexpected exception"); - - markupProcessor.insert ("errorType", "SHIRE Processing Error"); - markupProcessor.insert ("errorText", "Unexpected Exception"); - markupProcessor.insert ("errorDesc", "An error occurred while processing your request."); - if (cgi) delete cgi; - return shib_error_page (r, shireError.c_str(), markupProcessor); - } - - ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,0,r,"shire_post_handler() server error"); - return HTTP_INTERNAL_SERVER_ERROR; + while (!(ap_cfg_getline(l,MAX_STRING_LEN,f))) { + if ((*l=='#') || (!*l)) + continue; + ll = l; + apr_pool_clear(sp); + + group_name=ap_getword(sp,&ll,':'); + + while (*ll) { + w=ap_getword_conf(sp,&ll); + if (!strcmp(w,user)) { + apr_table_setn(grps,apr_pstrdup(r->pool,group_name),"in"); + break; + } + } + } + ap_cfg_closefile(f); + apr_pool_destroy(sp); + return grps; } /* @@ -758,190 +686,27 @@ extern "C" int shib_auth_checker(request_rec *r) return DECLINED; ostringstream threadid; - threadid << "[" << getpid() << "] shib" << '\0'; + threadid << "[" << getpid() << "] shibrm" << '\0'; saml::NDC ndc(threadid.str().c_str()); - ShibINI& ini = g_Config->getINI(); - - // This will always be normalized, because Apache uses ap_get_server_name - // in this API call. - const char* targeturl=ap_construct_url(r->pool,r->unparsed_uri,r); - - // Map request to application ID, which is the key for config lookup. - const char* application_id=get_application_id(r); - - // Ok, this is a SHIB target; grab the cookie - string shib_cookie; - if (!ini.get_tag(application_id, "cookieName", true, &shib_cookie)) { - ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,0,r, - "shib_check_user: no cookieName configuration for %s", - application_id); - return HTTP_INTERNAL_SERVER_ERROR; - } - - const char* session_id=NULL; - const char* cookies=apr_table_get(r->headers_in,"Cookie"); - if (!cookies || !(session_id=strstr(cookies,shib_cookie.c_str()))) - { - // No cookie??? Must be a server error! - ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,0,r, - "shib_auth_checker() no cookie found"); - - return HTTP_INTERNAL_SERVER_ERROR; - } - - // Yep, we found a cookie -- pull it out (our session_id) - session_id+=strlen(shib_cookie.c_str()) + 1; /* Skip over the '=' */ - char* cookiebuf = apr_pstrdup(r->pool,session_id); - char* cookieend = strchr(cookiebuf,';'); - if (cookieend) - *cookieend = '\0'; /* Ignore anyting after a ; */ - session_id=cookiebuf; - - ShibMLP markupProcessor; - string tag; - bool has_tag = ini.get_tag(application_id, "supportContact", true, &tag); - markupProcessor.insert("supportContact", has_tag ? tag : ""); - has_tag = ini.get_tag(application_id, "logoLocation", true, &tag); - markupProcessor.insert("logoLocation", has_tag ? tag : ""); - markupProcessor.insert("requestURL", targeturl); - - // Now grab the attributes... - has_tag = ini.get_tag (application_id, "checkIPAddress", true, &tag); - dc->rm_config.checkIPAddress = (has_tag ? ShibINI::boolean (tag) : false); - - RM rm(dc->rm_config); - - vector assertions; - SAMLAuthenticationStatement* sso_statement=NULL; - RPCError* status = rm.getAssertions(session_id, r->connection->remote_ip, application_id, assertions, &sso_statement); - - if (status->isError()) { - ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,0,r, - "shib_auth_checker() getAssertions failed: %s", - status->getText()); - - string rmError; - if (!ini.get_tag(application_id, "rmError", true, &rmError)) { - ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,0,r, - "shib_auth_checker: no rmError configuration for %s", - application_id); - delete status; - return HTTP_INTERNAL_SERVER_ERROR; - } - markupProcessor.insert(*status); - delete status; - return shib_error_page (r, rmError.c_str(), markupProcessor); - } - delete status; - - string rmError; - if (!ini.get_tag(application_id, "accessError", true, &rmError)) { - ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,0,r, - "shib_auth_checker: no accessError configuration for %s", - application_id); - - delete status; - for (int k = 0; k < assertions.size(); k++) - delete assertions[k]; - delete sso_statement; - return HTTP_INTERNAL_SERVER_ERROR; - } - - // Get the AAP providers, which contain the attribute policy info. - Iterator provs=g_Config->getAAPProviders(); - - // Clear out the list of mapped attributes - while (provs.hasNext()) - { - IAAP* aap=provs.next(); - aap->lock(); - try - { - Iterator rules=aap->getAttributeRules(); - while (rules.hasNext()) - { - const char* header=rules.next()->getHeader(); - if (header) - apr_table_unset(r->headers_in,header); - } - } - catch(...) - { - aap->unlock(); - for (int k = 0; k < assertions.size(); k++) - delete assertions[k]; - delete sso_statement; - throw; - } - aap->unlock(); - } - provs.reset(); + // We lock the configuration system for the duration. + IConfig* conf=g_Config->getINI(); + Locker locker(conf); - // Maybe export the first assertion. - apr_table_unset(r->headers_in,"Shib-Attributes"); - if (dc->bExportAssertion==1 && assertions.size()) { - string assertion; - RM::serialize(*(assertions[0]), assertion); - apr_table_set(r->headers_in,"Shib-Attributes", assertion.c_str()); - } - - // Export the SAML AuthnMethod and the origin site name. - apr_table_unset(r->headers_in,"Shib-Origin-Site"); - apr_table_unset(r->headers_in,"Shib-Authentication-Method"); - if (sso_statement) - { - auto_ptr_char os(sso_statement->getSubject()->getNameQualifier()); - auto_ptr_char am(sso_statement->getAuthMethod()); - apr_table_set(r->headers_in,"Shib-Origin-Site", os.get()); - apr_table_set(r->headers_in,"Shib-Authentication-Method", am.get()); + const char* application_id=apr_table_get(r->headers_in,"Shib-Application-ID"); + if (!application_id) { + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,0,r, + "shib_check_auth: Shib-Application-ID header not found in request"); + return HTTP_FORBIDDEN; } - apr_table_unset(r->headers_in,"Shib-Application-ID"); - apr_table_set(r->headers_in,"Shib-Application-ID",application_id); - - // Export the attributes. - Iterator a_iter(assertions); - while (a_iter.hasNext()) { - SAMLAssertion* assert=a_iter.next(); - Iterator statements=assert->getStatements(); - while (statements.hasNext()) { - SAMLAttributeStatement* astate=dynamic_cast(statements.next()); - if (!astate) - continue; - Iterator attrs=astate->getAttributes(); - while (attrs.hasNext()) { - SAMLAttribute* attr=attrs.next(); - - // Are we supposed to export it? - AAP wrapper(provs,attr->getName(),attr->getNamespace()); - if (wrapper.fail()) - continue; - - Iterator vals=attr->getSingleByteValues(); - if (!strcmp(wrapper->getHeader(),"REMOTE_USER") && vals.hasNext()) - r->user=apr_pstrdup(r->connection->pool,vals.next().c_str()); - else { - char* header = apr_pstrdup(r->pool, ""); - for (int it = 0; vals.hasNext(); it++) { - string value = vals.next(); - for (string::size_type pos = value.find_first_of(";", string::size_type(0)); pos != string::npos; pos = value.find_first_of(";", pos)) { - value.insert(pos, "\\"); - pos += 2; - } - header=apr_pstrcat(r->pool, header, (it ? ";" : ""), value.c_str(), NULL); - } - apr_table_setn(r->headers_in, wrapper->getHeader(), header); - } - } - } + const IApplication* application=conf->getApplication(application_id); + if (!application) { + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,0,r, + "shib_check_auth: unable to map request to application settings, check configuration"); + return HTTP_INTERNAL_SERVER_ERROR; } - // clean up memory - for (int k = 0; k < assertions.size(); k++) - delete assertions[k]; - delete sso_statement; - // mod_auth clone int m=r->method_number; @@ -955,12 +720,10 @@ extern "C" int shib_auth_checker(request_rec *r) require_line* reqs=(require_line*)reqs_arr->elts; //XXX - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "REQUIRE nelts: %d", reqs_arr->nelts); - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "REQUIRE all: %d", dc->bRequireAll); + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r,"REQUIRE nelts: %d", reqs_arr->nelts); + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r,"REQUIRE all: %d", dc->bRequireAll); - bool auth_OK[reqs_arr->nelts]; + vector auth_OK(reqs_arr->nelts,false); #define SHIB_AP_CHECK_IS_OK { \ if (dc->bRequireAll < 1) \ @@ -969,8 +732,7 @@ extern "C" int shib_auth_checker(request_rec *r) continue; \ } - for (int x=0; xnelts; x++) - { + for (int x=0; xnelts; x++) { auth_OK[x] = false; if (!(reqs[x].method_mask & (1 << m))) @@ -980,189 +742,168 @@ extern "C" int shib_auth_checker(request_rec *r) t = reqs[x].requirement; w = ap_getword_white(r->pool, &t); - if (!strcmp(w,"valid-user")) - { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shib_auth_checker() accepting valid-user"); - SHIB_AP_CHECK_IS_OK; + if (!strcmp(w,"valid-user")) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, "shib_auth_checker() accepting valid-user"); + SHIB_AP_CHECK_IS_OK; } - else if (!strcmp(w,"user") && r->user) - { + else if (!strcmp(w,"user") && r->user) { bool regexp=false; - while (*t) - { + while (*t) { w=ap_getword_conf(r->pool,&t); - if (*w=='~') - { + if (*w=='~') { regexp=true; continue; } - if (regexp) - { - try - { + if (regexp) { + try { // To do regex matching, we have to convert from UTF-8. auto_ptr trans(fromUTF8(w)); RegularExpression re(trans.get()); auto_ptr trans2(fromUTF8(r->user)); if (re.matches(trans2.get())) { ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shib_auth_checker() accepting user: %s",w); - SHIB_AP_CHECK_IS_OK; + "shib_auth_checker() accepting user: %s",w); + SHIB_AP_CHECK_IS_OK; } } - catch (XMLException& ex) - { + catch (XMLException& ex) { auto_ptr_char tmp(ex.getMessage()); ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,0,r, - "shib_auth_checker caught exception while parsing regular expression (%s): %s",w,tmp.get()); + "shib_auth_checker caught exception while parsing regular expression (%s): %s",w,tmp.get()); } } - else if (!strcmp(r->user,w)) - { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shib_auth_checker() accepting user: %s",w); - SHIB_AP_CHECK_IS_OK; + else if (!strcmp(r->user,w)) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r,"shib_auth_checker() accepting user: %s",w); + SHIB_AP_CHECK_IS_OK; } } } - else if (!strcmp(w,"group")) - { + else if (!strcmp(w,"group")) { apr_table_t* grpstatus=NULL; - if (dc->szAuthGrpFile && r->user) - { + if (dc->szAuthGrpFile && r->user) { ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shib_auth_checker() using groups file: %s\n", - dc->szAuthGrpFile); + "shib_auth_checker() using groups file: %s\n", dc->szAuthGrpFile); grpstatus=groups_for_user(r,r->user,dc->szAuthGrpFile); } if (!grpstatus) return DECLINED; - while (*t) - { + while (*t) { w=ap_getword_conf(r->pool,&t); - if (apr_table_get(grpstatus,w)) - { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shib_auth_checker() accepting group: %s",w); - SHIB_AP_CHECK_IS_OK; + if (apr_table_get(grpstatus,w)) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r,"shib_auth_checker() accepting group: %s",w); + SHIB_AP_CHECK_IS_OK; } } } - else - { + else { + Iterator provs=application->getAAPProviders(); AAP wrapper(provs,w); if (wrapper.fail()) { ap_log_rerror(APLOG_MARK,APLOG_WARNING|APLOG_NOERRNO,0,r, "shib_auth_checker() didn't recognize require rule: %s\n",w); - continue; + continue; } - bool regexp=false; - const char* vals=apr_table_get(r->headers_in,wrapper->getHeader()); - while (*t && vals) - { - w=ap_getword_conf(r->pool,&t); - if (*w=='~') - { - regexp=true; - continue; - } - - try - { - auto_ptr re; - if (regexp) - { - delete re.release(); - auto_ptr trans(fromUTF8(w)); - auto_ptr temp(new RegularExpression(trans.get())); - re=temp; - } + bool regexp=false; + const char* vals=apr_table_get(r->headers_in,wrapper->getHeader()); + while (*t && vals) { + w=ap_getword_conf(r->pool,&t); + if (*w=='~') { + regexp=true; + continue; + } + + try { + auto_ptr re; + if (regexp) { + delete re.release(); + auto_ptr trans(fromUTF8(w)); + auto_ptr temp(new RegularExpression(trans.get())); + re=temp; + } - string vals_str(vals); - int j = 0; - for (int i = 0; i < vals_str.length(); i++) - { - if (vals_str.at(i) == ';') - { - if (i == 0) { - ap_log_rerror(APLOG_MARK,APLOG_WARNING|APLOG_NOERRNO,0,r, - "shib_auth_checker() invalid header encoding %s: starts with semicolon", vals); - return HTTP_INTERNAL_SERVER_ERROR; - } + string vals_str(vals); + int j = 0; + for (int i = 0; i < vals_str.length(); i++) { + if (vals_str.at(i) == ';') { + if (i == 0) { + ap_log_rerror(APLOG_MARK,APLOG_WARNING|APLOG_NOERRNO,0,r, + "shib_auth_checker() invalid header encoding %s: starts with semicolon", vals); + return HTTP_INTERNAL_SERVER_ERROR; + } - if (vals_str.at(i-1) == '\\') { - vals_str.erase(i-1, 1); - i--; - continue; - } + if (vals_str.at(i-1) == '\\') { + vals_str.erase(i-1, 1); + i--; + continue; + } - string val = vals_str.substr(j, i-j); - j = i+1; - if (regexp) { - auto_ptr trans(fromUTF8(val.c_str())); - if (re->matches(trans.get())) { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shib_auth_checker() expecting %s, got %s: authorization granted", w, val.c_str()); - SHIB_AP_CHECK_IS_OK; - } - } - else if (val==w) { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shib_auth_checker() expecting %s, got %s: authorization granted", w, val.c_str()); - SHIB_AP_CHECK_IS_OK; - } - else { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shib_auth_checker() expecting %s, got %s: authorization not granted", w, val.c_str()); - } - } - } + string val = vals_str.substr(j, i-j); + j = i+1; + if (regexp) { + auto_ptr trans(fromUTF8(val.c_str())); + if (re->matches(trans.get())) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, + "shib_auth_checker() expecting %s, got %s: authorization granted", w, val.c_str()); + SHIB_AP_CHECK_IS_OK; + } + } + else if (val==w) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, + "shib_auth_checker() expecting %s, got %s: authorization granted", w, val.c_str()); + SHIB_AP_CHECK_IS_OK; + } + else { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, + "shib_auth_checker() expecting %s, got %s: authorization not granted", w, val.c_str()); + } + } + } - string val = vals_str.substr(j, vals_str.length()-j); - if (regexp) { - auto_ptr trans(fromUTF8(val.c_str())); - if (re->matches(trans.get())) { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shib_auth_checker() expecting %s, got %s: authorization granted", w, val.c_str()); - SHIB_AP_CHECK_IS_OK; - } - } - else if (val==w) { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shib_auth_checker() expecting %s, got %s: authorization granted", w, val.c_str()); - SHIB_AP_CHECK_IS_OK; - } - else { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, - "shib_auth_checker() expecting %s, got %s: authorization not granted", w, val.c_str()); - } - } - catch (XMLException& ex) - { - auto_ptr tmp(XMLString::transcode(ex.getMessage())); - ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,0,r, - "shib_auth_checker caught exception while parsing regular expression (%s): %s",w,tmp.get()); - } - } - } + string val = vals_str.substr(j, vals_str.length()-j); + if (regexp) { + auto_ptr trans(fromUTF8(val.c_str())); + if (re->matches(trans.get())) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, + "shib_auth_checker() expecting %s, got %s: authorization granted", w, val.c_str()); + SHIB_AP_CHECK_IS_OK; + } + } + else if (val==w) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, + "shib_auth_checker() expecting %s, got %s: authorization granted", w, val.c_str()); + SHIB_AP_CHECK_IS_OK; + } + else { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, + "shib_auth_checker() expecting %s, got %s: authorization not granted", w, val.c_str()); + } + } + catch (XMLException& ex) { + auto_ptr_char tmp(ex.getMessage()); + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,0,r, + "shib_auth_checker caught exception while parsing regular expression (%s): %s",w,tmp.get()); + } + } + } } // check if all require directives are true bool auth_all_OK = true; for (int i= 0; inelts; i++) { auth_all_OK &= auth_OK[i]; - } + } if (auth_all_OK) return OK; if (!method_restricted) return OK; - return shib_error_page(r, rmError.c_str(), markupProcessor); + ShibMLP markupProcessor(application); + markupProcessor.insert("requestURL", ap_construct_url(r->pool,r->unparsed_uri,r)); + return shib_error_page(r, application, "access", markupProcessor); } /* @@ -1177,6 +918,15 @@ extern "C" apr_status_t shib_exit(void* data) return OK; } +static const XMLCh Apache[] = +{ chLatin_A, chLatin_p, chLatin_a, chLatin_c, chLatin_h, chLatin_e, chNull }; +static const XMLCh apacheConfig[] = +{ chLatin_a, chLatin_p, chLatin_a, chLatin_c, chLatin_h, chLatin_e, + chLatin_C, chLatin_o, chLatin_n, chLatin_f, chLatin_i, chLatin_g, 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 }; + /* * shib_post_config() * Things to do at process startup after the configs are read @@ -1186,22 +936,45 @@ extern "C" int shib_post_config(apr_pool_t* pconf, apr_pool_t* plog, { // Initialize runtime components. - ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,s, - "shib_post_config() starting"); - - ShibTargetConfig::preinit(); + ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,s,"shib_post_config() starting"); if (g_Config) { - ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,0,s, - "shib_post_config(): already initialized!"); - exit (1); + ap_log_error(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,0,s,"shib_post_config(): already initialized"); + return OK; } try { - g_Config = &(ShibTargetConfig::init(SHIBTARGET_SHIRE, g_szSHIBConfig)); - } catch (...) { + g_Config=&ShibTargetConfig::getConfig(); + g_Config->setFeatures( + ShibTargetConfig::Listener | + ShibTargetConfig::Metadata | + ShibTargetConfig::AAP | + ShibTargetConfig::RequestMapper | + ShibTargetConfig::SHIREExtensions + ); + if (!g_Config->init(g_szSchemaDir,g_szSHIBConfig)) { + ap_log_error(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,0,s,"shib_post_config(): already initialized!"); + exit(1); + } + + // Access the implementation-specifics for whether to use old Apache config style... + IConfig* conf=g_Config->getINI(); + Locker locker(conf); + const IPropertySet* props=conf->getPropertySet("SHIRE"); + if (props) { + const DOMElement* impl=saml::XML::getFirstChildElement( + props->getElement(),ShibTargetConfig::SHIBTARGET_NS,Implementation + ); + if (impl && (impl=saml::XML::getFirstChildElement(impl,ShibTargetConfig::SHIBTARGET_NS,Apache))) { + const XMLCh* flag=impl->getAttributeNS(NULL,apacheConfig); + if (flag && (*flag==chDigit_1 || *flag==chLatin_t)) + g_bApacheConf=true; + } + } + } + catch (...) { ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,s, - "shib_post_config() failed to initialize SHIB Target"); + "shib_post_config() failed to initialize SHIB Target"); exit (1); } @@ -1218,40 +991,35 @@ extern "C" void shib_register_hooks (apr_pool_t *p) ap_hook_post_config(shib_post_config, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_check_user_id(shib_check_user, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_auth_checker(shib_auth_checker, NULL, NULL, APR_HOOK_FIRST); - ap_hook_handler(shib_shire_handler, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_handler(shib_post_handler, NULL, NULL, APR_HOOK_LAST); } // SHIB Module commands extern "C" { static command_rec shib_cmds[] = { - AP_INIT_TAKE1("SHIBConfig", + AP_INIT_TAKE1("ShibConfig", (config_fn_t)ap_set_global_string_slot, &g_szSHIBConfig, - RSRC_CONF, "Path to SHIB ini file."), + RSRC_CONF, "Path to shibboleth.xml config file."), + AP_INIT_TAKE1("ShibSchemaDir", + (config_fn_t)ap_set_global_string_slot, &g_szSchemaDir, + RSRC_CONF, "Path to Shibboleth XML schema directory."), AP_INIT_FLAG("ShibBasicHijack", (config_fn_t)ap_set_flag_slot, (void *) offsetof (shib_dir_config, bBasicHijack), OR_AUTHCFG, "Respond to AuthType Basic and convert to shib?"), - AP_INIT_FLAG("ShibSSLOnly", (config_fn_t)ap_set_flag_slot, - (void *) offsetof (shib_dir_config, bSSLOnly), - OR_AUTHCFG, "Require SSL when accessing a secured directory?"), - AP_INIT_TAKE1("ShibAuthLifetime", (config_fn_t)set_lifetime, NULL, - OR_AUTHCFG, "Lifetime of session in seconds."), - AP_INIT_TAKE1("ShibAuthTimeout", (config_fn_t)set_timeout, NULL, - OR_AUTHCFG, "Timeout for session in seconds."), - + AP_INIT_FLAG("ShibRequireSession", (config_fn_t)ap_set_flag_slot, + (void *) offsetof (shib_dir_config, bRequireSession), + OR_AUTHCFG, "Initiates a new session if one does not exist."), + AP_INIT_FLAG("ShibExportAssertion", (config_fn_t)ap_set_flag_slot, + (void *) offsetof (shib_dir_config, bExportAssertion), + OR_AUTHCFG, "Export SAML assertion to Shibboleth-defined header?"), AP_INIT_TAKE1("AuthGroupFile", (config_fn_t)ap_set_file_slot, (void *) offsetof (shib_dir_config, szAuthGrpFile), OR_AUTHCFG, "text file containing group names and member user IDs"), - AP_INIT_FLAG("ShibExportAssertion", (config_fn_t)ap_set_flag_slot, - (void *) offsetof (shib_dir_config, bExportAssertion), - OR_AUTHCFG, "Export SAML assertion to Shibboleth-defined header?"), AP_INIT_FLAG("ShibRequireAll", (config_fn_t)ap_set_flag_slot, (void *) offsetof (shib_dir_config, bRequireAll), OR_AUTHCFG, "All require directives must match!"), - AP_INIT_FLAG("DisableRM", (config_fn_t)ap_set_flag_slot, - (void *) offsetof (shib_dir_config, bDisableRM), - OR_AUTHCFG, "Disable the Shibboleth Resource Manager?"), {NULL} }; diff --git a/mod_shibrm/.cvsignore b/mod_shibrm/.cvsignore deleted file mode 100644 index 68bff54..0000000 --- a/mod_shibrm/.cvsignore +++ /dev/null @@ -1,9 +0,0 @@ -Makefile.in -Makefile -.libs -.deps -*.lo -*.la -Debug -*.plg -Release diff --git a/mod_shibrm/Makefile.am b/mod_shibrm/Makefile.am deleted file mode 100644 index 7ddcee7..0000000 --- a/mod_shibrm/Makefile.am +++ /dev/null @@ -1,25 +0,0 @@ -## $Id$ - -AUTOMAKE_OPTIONS = foreign - -if USE_OUR_ONCRPC -RPC_CFLAGS = -I${top_srcdir}/oncrpc -endif - -shibrmdir = $(libexecdir) -shibrm_LTLIBRARIES = mod_shibrm.la - -mod_shibrm_la_SOURCES = mod_shibrm.cpp - -AM_CXXFLAGS = $(APXS_CFLAGS) -I$(APXS_INCLUDE) $(RPC_CFLAGS) - -mod_shibrm_la_LIBADD = $(top_builddir)/shib/libshib.la $(top_builddir)/shib-target/libshib-target.la - -mod_shibrm_la_LDFLAGS = -module -avoid-version -lapreq - -if DO_APXS_INSTALL -install-exec-local: - $(APXS) -i -A -n shibrm .libs/mod_shibrm.so -endif - -EXTRA_DIST = mod_shibrm.dsp diff --git a/mod_shibrm/mod_shibrm.cpp b/mod_shibrm/mod_shibrm.cpp deleted file mode 100644 index 272cf23..0000000 --- a/mod_shibrm/mod_shibrm.cpp +++ /dev/null @@ -1,604 +0,0 @@ -/* - * mod_shibrm.cpp -- the SHIB Resource Manager Apache Module - * - * Created by: Derek Atkins - * - * $Id$ - */ - -// SAML Runtime -#include -#include -#include -#include - -// Apache specific header files -#include "httpd.h" -#include "http_config.h" -#include "http_main.h" -#include "http_protocol.h" -#include "util_script.h" -#define CORE_PRIVATE -#include "http_core.h" -#include "http_log.h" - -#include - -#include -#include -#include - -using namespace std; -using namespace saml; -using namespace shibboleth; -using namespace shibtarget; - -namespace { - ShibTargetConfig* g_Config = NULL; -} - -extern "C" module MODULE_VAR_EXPORT shibrm_module; - -// per-dir module configuration structure -struct shibrm_dir_config -{ - char* szAuthGrpFile; // Auth GroupFile name - int bExportAssertion; // export SAML assertion to the environment? - RMConfig config; // Resource Manager Configuration -}; - -// creates per-directory config structure -extern "C" void* create_shibrm_dir_config (pool* p, char* d) -{ - shibrm_dir_config* dc=(shibrm_dir_config*)ap_pcalloc(p,sizeof(shibrm_dir_config)); - dc->szAuthGrpFile = NULL; - dc->bExportAssertion = -1; - return dc; -} - -// overrides server configuration in directories -extern "C" void* merge_shibrm_dir_config (pool* p, void* base, void* sub) -{ - shibrm_dir_config* dc=(shibrm_dir_config*)ap_pcalloc(p,sizeof(shibrm_dir_config)); - shibrm_dir_config* parent=(shibrm_dir_config*)base; - shibrm_dir_config* child=(shibrm_dir_config*)sub; - - if (child->szAuthGrpFile) - dc->szAuthGrpFile=ap_pstrdup(p,child->szAuthGrpFile); - else if (parent->szAuthGrpFile) - dc->szAuthGrpFile=ap_pstrdup(p,parent->szAuthGrpFile); - else - dc->szAuthGrpFile=NULL; - - dc->bExportAssertion=((child->bExportAssertion==-1) ? parent->bExportAssertion : child->bExportAssertion); - return dc; -} - -typedef const char* (*config_fn_t)(void); - -// SHIBRM Module commands - -static command_rec shibrm_cmds[] = { - {"AuthGroupFile", (config_fn_t)ap_set_file_slot, - (void *) XtOffsetOf (shibrm_dir_config, szAuthGrpFile), - OR_AUTHCFG, TAKE1, "text file containing group names and member user IDs"}, - {"ShibExportAssertion", (config_fn_t)ap_set_flag_slot, - (void *) XtOffsetOf (shibrm_dir_config, bExportAssertion), - OR_AUTHCFG, FLAG, "Export SAML assertion to Shibboleth-defined header?"}, - - {NULL} -}; - -/* - * shibrm_child_init() - * Things to do when the child process is initialized. - */ -extern "C" void shibrm_child_init(server_rec* s, pool* p) -{ - ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s, - "shibrm_child_init() starting"); - - if (g_Config) { - ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,s, - "shibrm_child_init(): already initialized!"); - exit (1); - } - - try { - // Assume that we've been initialized from the SHIRE module! - g_Config = &(ShibTargetConfig::init(SHIBTARGET_RM, "NOOP")); - } catch (...) { - ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s, - "shibrm_child_init() failed to initialize SHIB Target"); - exit (1); - } - - saml::NDC ndc("shibrm_child_init"); - - ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s,"shibrm_child_init() done"); -} - - -/* - * shibrm_child_exit() - * Cleanup. - */ -extern "C" void shibrm_child_exit(server_rec* s, pool* p) -{ - g_Config->shutdown(); - g_Config = NULL; - ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s,"shibrm_child_exit() done"); -} - -static table* groups_for_user(request_rec* r, const char* user, char* grpfile) -{ - configfile_t* f; - table* grps=ap_make_table(r->pool,15); - char l[MAX_STRING_LEN]; - const char *group_name, *ll, *w; - - if (!(f=ap_pcfg_openfile(r->pool,grpfile))) - { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG,r,"groups_for_user() could not open group file: %s\n", - grpfile); - return NULL; - } - - pool* sp=ap_make_sub_pool(r->pool); - - while (!(ap_cfg_getline(l,MAX_STRING_LEN,f))) - { - if ((*l=='#') || (!*l)) - continue; - ll = l; - ap_clear_pool(sp); - - group_name=ap_getword(sp,&ll,':'); - - while (*ll) - { - w=ap_getword_conf(sp,&ll); - if (!strcmp(w,user)) - { - ap_table_setn(grps,ap_pstrdup(r->pool,group_name),"in"); - break; - } - } - } - ap_cfg_closefile(f); - ap_destroy_pool(sp); - return grps; -} - -static int shibrm_error_page(request_rec* r, const char* filename, ShibMLP& mlp) -{ - ifstream infile (filename); - if (!infile) { - ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r, - "shibrm_error_page() cannot open %s", filename); - return SERVER_ERROR; - } - - string res = mlp.run(infile); - r->content_type = ap_psprintf(r->pool, "text/html"); - ap_send_http_header(r); - ap_rprintf(r, res.c_str()); - return DONE; -} - -static const char* get_application_id(request_rec* r) -{ - ApplicationMapper mapper; - return ap_pstrdup(r->pool, - mapper->getApplicationFromParsedURL( - ap_http_method(r), ap_get_server_name(r), ap_get_server_port(r), r->unparsed_uri - ) - ); -} - -extern "C" int shibrm_check_auth(request_rec* r) -{ - shibrm_dir_config* dc= - (shibrm_dir_config*)ap_get_module_config(r->per_dir_config,&shibrm_module); - - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, - "shibrm_check_auth() executing"); - - // Regular access to arbitrary resource...check AuthType - const char* auth_type=ap_auth_type(r); - if (!auth_type || strcasecmp(auth_type,"shibboleth")) - return DECLINED; - - ostringstream threadid; - threadid << "[" << getpid() << "] shibrm" << '\0'; - saml::NDC ndc(threadid.str().c_str()); - - ShibINI& ini = g_Config->getINI(); - - // This will always be normalized, because Apache uses ap_get_server_name in this API call. - const char* targeturl=ap_construct_url(r->pool,r->unparsed_uri,r); - - // Map request to application ID, which is the key for config lookup. - const char* application_id=get_application_id(r); - - // Ok, this is a SHIB target; grab the cookie - string shib_cookie; - if (!ini.get_tag(application_id, "cookieName", true, &shib_cookie)) { - ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r, - "shibrm_check_user: no cookieName configuration for %s", application_id); - return SERVER_ERROR; - } - - const char* session_id=NULL; - const char* cookies=ap_table_get(r->headers_in,"Cookie"); - if (!cookies || !(session_id=strstr(cookies,shib_cookie.c_str()))) - { - // No cookie??? Must be a server error! - ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"shibrm_check_auth() no cookie found"); - return SERVER_ERROR; - } - - // Yep, we found a cookie -- pull it out (our session_id) - session_id+=strlen(shib_cookie.c_str()) + 1; /* Skip over the '=' */ - char* cookiebuf = ap_pstrdup(r->pool,session_id); - char* cookieend = strchr(cookiebuf,';'); - if (cookieend) - *cookieend = '\0'; /* Ignore anyting after a ; */ - session_id=cookiebuf; - - ShibMLP markupProcessor; - string tag; - bool has_tag = ini.get_tag(application_id, "supportContact", true, &tag); - markupProcessor.insert("supportContact", has_tag ? tag : ""); - has_tag = ini.get_tag(application_id, "logoLocation", true, &tag); - markupProcessor.insert("logoLocation", has_tag ? tag : ""); - markupProcessor.insert("requestURL", targeturl); - - // Now grab the attributes... - has_tag = ini.get_tag (application_id, "checkIPAddress", true, &tag); - dc->config.checkIPAddress = (has_tag ? ShibINI::boolean (tag) : false); - - RM rm(dc->config); - - vector assertions; - SAMLAuthenticationStatement* sso_statement=NULL; - RPCError* status = rm.getAssertions(session_id, r->connection->remote_ip, application_id, assertions, &sso_statement); - - if (status->isError()) { - ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r, - "shibrm_check_auth() getAssertions failed: %s", - status->getText()); - - string rmError; - if (!ini.get_tag(application_id, "rmError", true, &rmError)) { - ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r, - "shibrm_check_auth: no rmError configuration for %s", application_id); - delete status; - return SERVER_ERROR; - } - markupProcessor.insert(*status); - delete status; - return shibrm_error_page (r, rmError.c_str(), markupProcessor); - } - delete status; - - string rmError; - if (!ini.get_tag(application_id, "accessError", true, &rmError)) { - ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r, - "shibrm_check_auth: no accessError configuration for %s", application_id); - - delete status; - for (int k = 0; k < assertions.size(); k++) - delete assertions[k]; - delete sso_statement; - return SERVER_ERROR; - } - - // Get the AAP providers, which contain the attribute policy info. - Iterator provs=g_Config->getAAPProviders(); - - // Clear out the list of mapped attributes - while (provs.hasNext()) - { - IAAP* aap=provs.next(); - aap->lock(); - try - { - Iterator rules=aap->getAttributeRules(); - while (rules.hasNext()) - { - const char* header=rules.next()->getHeader(); - if (header) - ap_table_unset(r->headers_in,header); - } - } - catch(...) - { - aap->unlock(); - for (int k = 0; k < assertions.size(); k++) - delete assertions[k]; - delete sso_statement; - throw; - } - aap->unlock(); - } - provs.reset(); - - // Maybe export the first assertion. - ap_table_unset(r->headers_in,"Shib-Attributes"); - if (dc->bExportAssertion==1 && assertions.size()) { - string assertion; - RM::serialize(*(assertions[0]), assertion); - ap_table_set(r->headers_in,"Shib-Attributes", assertion.c_str()); - } - - // Export the SAML AuthnMethod and the origin site name. - ap_table_unset(r->headers_in,"Shib-Origin-Site"); - ap_table_unset(r->headers_in,"Shib-Authentication-Method"); - if (sso_statement) - { - auto_ptr_char os(sso_statement->getSubject()->getNameQualifier()); - auto_ptr_char am(sso_statement->getAuthMethod()); - ap_table_set(r->headers_in,"Shib-Origin-Site", os.get()); - ap_table_set(r->headers_in,"Shib-Authentication-Method", am.get()); - } - - ap_table_unset(r->headers_in,"Shib-Application-ID"); - ap_table_set(r->headers_in,"Shib-Application-ID",application_id); - - // Export the attributes. - Iterator a_iter(assertions); - while (a_iter.hasNext()) { - SAMLAssertion* assert=a_iter.next(); - Iterator statements=assert->getStatements(); - while (statements.hasNext()) { - SAMLAttributeStatement* astate=dynamic_cast(statements.next()); - if (!astate) - continue; - Iterator attrs=astate->getAttributes(); - while (attrs.hasNext()) { - SAMLAttribute* attr=attrs.next(); - - // Are we supposed to export it? - AAP wrapper(provs,attr->getName(),attr->getNamespace()); - if (wrapper.fail()) - continue; - - Iterator vals=attr->getSingleByteValues(); - if (!strcmp(wrapper->getHeader(),"REMOTE_USER") && vals.hasNext()) - r->connection->user=ap_pstrdup(r->connection->pool,vals.next().c_str()); - else { - char* header = ap_pstrdup(r->pool, ""); - for (int it = 0; vals.hasNext(); it++) { - string value = vals.next(); - for (string::size_type pos = value.find_first_of(";", string::size_type(0)); pos != string::npos; pos = value.find_first_of(";", pos)) { - value.insert(pos, "\\"); - pos += 2; - } - header=ap_pstrcat(r->pool, header, (it ? ";" : ""), value.c_str(), NULL); - } - ap_table_setn(r->headers_in, wrapper->getHeader(), header); - } - } - } - } - - // clean up memory - for (int k = 0; k < assertions.size(); k++) - delete assertions[k]; - delete sso_statement; - - // mod_auth clone - - int m=r->method_number; - bool method_restricted=false; - const char *t, *w; - - const array_header* reqs_arr=ap_requires(r); - if (!reqs_arr) - return OK; - - require_line* reqs=(require_line*)reqs_arr->elts; - - for (int x=0; xnelts; x++) - { - if (!(reqs[x].method_mask & (1 << m))) - continue; - method_restricted=true; - - t = reqs[x].requirement; - w = ap_getword_white(r->pool, &t); - - if (!strcmp(w,"valid-user")) - { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shibrm_check_auth() accepting valid-user"); - return OK; - } - else if (!strcmp(w,"user") && r->connection->user) - { - bool regexp=false; - while (*t) - { - w=ap_getword_conf(r->pool,&t); - if (*w=='~') - { - regexp=true; - continue; - } - - if (regexp) - { - try - { - // To do regex matching, we have to convert from UTF-8. - auto_ptr trans(fromUTF8(w)); - RegularExpression re(trans.get()); - auto_ptr trans2(fromUTF8(r->connection->user)); - if (re.matches(trans2.get())) { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shibrm_check_auth() accepting user: %s",w); - return OK; - } - } - catch (XMLException& ex) - { - auto_ptr_char tmp(ex.getMessage()); - ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r, - "shibrm_check_auth caught exception while parsing regular expression (%s): %s",w,tmp.get()); - } - } - else if (!strcmp(r->connection->user,w)) - { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shibrm_check_auth() accepting user: %s",w); - return OK; - } - } - } - else if (!strcmp(w,"group")) - { - table* grpstatus=NULL; - if (dc->szAuthGrpFile && r->connection->user) - { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shibrm_check_auth() using groups file: %s\n", - dc->szAuthGrpFile); - grpstatus=groups_for_user(r,r->connection->user,dc->szAuthGrpFile); - } - if (!grpstatus) - return DECLINED; - - while (*t) - { - w=ap_getword_conf(r->pool,&t); - if (ap_table_get(grpstatus,w)) - { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shibrm_check_auth() accepting group: %s",w); - return OK; - } - } - } - else - { - AAP wrapper(provs,w); - if (wrapper.fail()) { - ap_log_rerror(APLOG_MARK,APLOG_WARNING|APLOG_NOERRNO,r, - "shibrm_check_auth() didn't recognize require rule: %s\n",w); - continue; - } - - bool regexp=false; - const char* vals=ap_table_get(r->headers_in,wrapper->getHeader()); - while (*t && vals) { - w=ap_getword_conf(r->pool,&t); - if (*w=='~') { - regexp=true; - continue; - } - - try { - auto_ptr re; - if (regexp) { - delete re.release(); - auto_ptr trans(fromUTF8(w)); - auto_ptr temp(new RegularExpression(trans.get())); - re=temp; - } - - string vals_str(vals); - int j = 0; - for (int i = 0; i < vals_str.length(); i++) { - if (vals_str.at(i) == ';') { - if (i == 0) { - ap_log_rerror(APLOG_MARK,APLOG_WARNING|APLOG_NOERRNO,r, - "shibrm_check_auth() invalid header encoding %s: starts with semicolon", vals); - return SERVER_ERROR; - } - - if (vals_str.at(i-1) == '\\') { - vals_str.erase(i-1, 1); - i--; - continue; - } - - string val = vals_str.substr(j, i-j); - j = i+1; - if (regexp) { - auto_ptr trans(fromUTF8(val.c_str())); - if (re->matches(trans.get())) { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, - "shibrm_check_auth() expecting %s, got %s: authorization granted", w, val.c_str()); - return OK; - } - } - else if (val==w) { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, - "shibrm_check_auth() expecting %s, got %s: authorization granted", w, val.c_str()); - return OK; - } - else { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, - "shibrm_check_auth() expecting %s, got %s: authorization not granted", w, val.c_str()); - } - } - } - - string val = vals_str.substr(j, vals_str.length()-j); - if (regexp) { - auto_ptr trans(fromUTF8(val.c_str())); - if (re->matches(trans.get())) { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, - "shibrm_check_auth() expecting %s, got %s: authorization granted", w, val.c_str()); - return OK; - } - } - else if (val==w) { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, - "shibrm_check_auth() expecting %s, got %s: authorization granted", w, val.c_str()); - return OK; - } - else { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, - "shibrm_check_auth() expecting %s, got %s: authorization not granted", w, val.c_str()); - } - } - catch (XMLException& ex) { - auto_ptr tmp(XMLString::transcode(ex.getMessage())); - ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r, - "shibrm_check_auth caught exception while parsing regular expression (%s): %s",w,tmp.get()); - } - } - } - } - - if (!method_restricted) - return OK; - - return shibrm_error_page(r, rmError.c_str(), markupProcessor); -} - -extern "C" void mod_shibrm_init (server_rec*r, pool* p) -{ - ShibTargetConfig::preinit(); -} - -extern "C"{ -module MODULE_VAR_EXPORT shibrm_module = { - STANDARD_MODULE_STUFF, - mod_shibrm_init, /* initializer */ - create_shibrm_dir_config, /* dir config creater */ - merge_shibrm_dir_config, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - shibrm_cmds, /* command table */ - NULL, /* handlers */ - NULL, /* filename translation */ - NULL, /* check_user_id */ - shibrm_check_auth, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - NULL, /* fixups */ - NULL, /* logger */ - NULL, /* header parser */ - shibrm_child_init, /* child_init */ - shibrm_child_exit, /* child_exit */ - NULL /* post read-request */ -}; -} diff --git a/mod_shibrm/mod_shibrm.dsp b/mod_shibrm/mod_shibrm.dsp deleted file mode 100644 index ed17082..0000000 --- a/mod_shibrm/mod_shibrm.dsp +++ /dev/null @@ -1,95 +0,0 @@ -# Microsoft Developer Studio Project File - Name="mod_shibrm" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=mod_shibrm - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "mod_shibrm.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_shibrm.mak" CFG="mod_shibrm - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_shibrm - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_shibrm - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "mod_shibrm - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MOD_SHIBRM_EXPORTS" /YX /FD /c -# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I "..\oncrpc" /I ".." /I "..\..\..\opensaml\c" /I "\Apache\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "EAPI" /YX /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# 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 /nologo /dll /machine:I386 -# ADD LINK32 log4cpp.lib xerces-c_2.lib ApacheCore.lib saml_4.lib /nologo /dll /machine:I386 /libpath:"../../../opensaml/c/saml/Release" /libpath:"\Apache\libexec" - -!ELSEIF "$(CFG)" == "mod_shibrm - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MOD_SHIBRM_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /ZI /Od /I "..\oncrpc" /I ".." /I "..\..\..\opensaml\c" /I "\Apache\include" /D "_DEBUG" /D "_AFXDLL" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "EAPI" /FR /YX /FD /GZ /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# 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 /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 log4cppD.lib xerces-c_2D.lib ApacheCore.lib saml_4D.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /libpath:"../../../opensaml/c/saml/Debug" /libpath:"\Apache\libexec" - -!ENDIF - -# Begin Target - -# Name "mod_shibrm - Win32 Release" -# Name "mod_shibrm - Win32 Debug" -# Begin Source File - -SOURCE=.\mod_shibrm.cpp -# End Source File -# End Target -# End Project diff --git a/mod_shire/mod_shire.cpp b/mod_shire/mod_shire.cpp index 7e7204c..354beb8 100644 --- a/mod_shire/mod_shire.cpp +++ b/mod_shire/mod_shire.cpp @@ -11,24 +11,19 @@ #include #include #include +#include // Apache specific header files -#include "httpd.h" -#include "http_config.h" -#include "http_protocol.h" -#include "http_main.h" -#include "util_script.h" +#include +#include +#include +#include #define CORE_PRIVATE -#include "http_core.h" -#include "http_log.h" +#include +#include #include #include -#include - -// For POST processing from Apache -#undef _XOPEN_SOURCE // bombs on solaris -#include using namespace std; using namespace saml; @@ -36,19 +31,26 @@ using namespace shibboleth; using namespace shibtarget; extern "C" module MODULE_VAR_EXPORT shire_module; +int shire_handler(request_rec* r, const IApplication* application, const IPropertySet* sessionProps, SHIRE& shire); namespace { - char* g_szSHIREURL = NULL; - char* g_szSHIREConfig = NULL; + char* g_szSHIBConfig = NULL; + char* g_szSchemaDir = NULL; ShibTargetConfig* g_Config = NULL; + bool g_bApacheConf = false; } // per-dir module configuration structure struct shire_dir_config { - int bBasicHijack; // activate for AuthType Basic? - int bSSLOnly; // only over SSL? - SHIREConfig config; // SHIRE Configuration + // RM Configuration + char* szAuthGrpFile; // Auth GroupFile name + int bRequireAll; // all require directives must match, otherwise OR logic + + // SHIRE Configuration + int bBasicHijack; // activate for AuthType Basic? + int bRequireSession; // require a session? + int bExportAssertion; // export SAML assertion to the environment? }; // creates per-directory config structure @@ -56,9 +58,10 @@ extern "C" void* create_shire_dir_config (pool* p, char* d) { shire_dir_config* dc=(shire_dir_config*)ap_pcalloc(p,sizeof(shire_dir_config)); dc->bBasicHijack = -1; - dc->bSSLOnly = -1; - dc->config.lifetime = -1; - dc->config.timeout = -1; + dc->bRequireSession = -1; + dc->bExportAssertion = -1; + dc->bRequireAll = -1; + dc->szAuthGrpFile = NULL; return dc; } @@ -69,10 +72,17 @@ extern "C" void* merge_shire_dir_config (pool* p, void* base, void* sub) shire_dir_config* parent=(shire_dir_config*)base; shire_dir_config* child=(shire_dir_config*)sub; + if (child->szAuthGrpFile) + dc->szAuthGrpFile=ap_pstrdup(p,child->szAuthGrpFile); + else if (parent->szAuthGrpFile) + dc->szAuthGrpFile=ap_pstrdup(p,parent->szAuthGrpFile); + else + dc->szAuthGrpFile=NULL; + dc->bBasicHijack=((child->bBasicHijack==-1) ? parent->bBasicHijack : child->bBasicHijack); - dc->bSSLOnly=((child->bSSLOnly==-1) ? parent->bSSLOnly : child->bSSLOnly); - dc->config.lifetime=((child->config.lifetime==-1) ? parent->config.lifetime : child->config.lifetime); - dc->config.timeout=((child->config.timeout==-1) ? parent->config.timeout : child->config.timeout); + dc->bRequireSession=((child->bRequireSession==-1) ? parent->bRequireSession : child->bRequireSession); + dc->bExportAssertion=((child->bExportAssertion==-1) ? parent->bExportAssertion : child->bExportAssertion); + dc->bRequireAll=((child->bRequireAll==-1) ? parent->bRequireAll : child->bRequireAll); return dc; } @@ -83,43 +93,46 @@ extern "C" const char* ap_set_global_string_slot(cmd_parms* parms, void*, const return NULL; } -// some shortcuts for directory config slots -extern "C" const char* set_lifetime(cmd_parms* parms, shire_dir_config* dc, const char* arg) -{ - dc->config.lifetime=atoi(arg); - return NULL; -} - -extern "C" const char* set_timeout(cmd_parms* parms, shire_dir_config* dc, const char* arg) -{ - dc->config.timeout=atoi(arg); - return NULL; -} - typedef const char* (*config_fn_t)(void); // SHIRE Module commands static command_rec shire_cmds[] = { - {"SHIREConfig", (config_fn_t)ap_set_global_string_slot, &g_szSHIREConfig, - RSRC_CONF, TAKE1, "Path to SHIRE ini file."}, - {"SHIREURL", (config_fn_t)ap_set_global_string_slot, &g_szSHIREURL, - RSRC_CONF, TAKE1, "SHIRE POST processor URL."}, + {"SHIREConfig", (config_fn_t)ap_set_global_string_slot, &g_szSHIBConfig, + RSRC_CONF, TAKE1, "Path to shibboleth.xml config file."}, + {"ShibConfig", (config_fn_t)ap_set_global_string_slot, &g_szSHIBConfig, + RSRC_CONF, TAKE1, "Path to shibboleth.xml config file."}, + {"ShibSchemaDir", (config_fn_t)ap_set_global_string_slot, &g_szSchemaDir, + RSRC_CONF, TAKE1, "Path to Shibboleth XML schema directory."}, {"ShibBasicHijack", (config_fn_t)ap_set_flag_slot, (void *) XtOffsetOf (shire_dir_config, bBasicHijack), OR_AUTHCFG, FLAG, "Respond to AuthType Basic and convert to shib?"}, - {"ShibSSLOnly", (config_fn_t)ap_set_flag_slot, - (void *) XtOffsetOf (shire_dir_config, bSSLOnly), - OR_AUTHCFG, FLAG, "Require SSL when accessing a secured directory?"}, - {"ShibAuthLifetime", (config_fn_t)set_lifetime, NULL, - OR_AUTHCFG, TAKE1, "Lifetime of session in seconds."}, - {"ShibAuthTimeout", (config_fn_t)set_timeout, NULL, - OR_AUTHCFG, TAKE1, "Timeout for session in seconds."}, + {"ShibRequireSession", (config_fn_t)ap_set_flag_slot, + (void *) XtOffsetOf (shire_dir_config, bRequireSession), + OR_AUTHCFG, FLAG, "Initiates a new session if one does not exist."}, + {"ShibExportAssertion", (config_fn_t)ap_set_flag_slot, + (void *) XtOffsetOf (shire_dir_config, bExportAssertion), + OR_AUTHCFG, FLAG, "Export SAML assertion to Shibboleth-defined header?"}, + {"AuthGroupFile", (config_fn_t)ap_set_file_slot, + (void *) XtOffsetOf (shire_dir_config, szAuthGrpFile), + OR_AUTHCFG, TAKE1, "text file containing group names and member user IDs"}, + {"ShibRequireAll", (config_fn_t)ap_set_flag_slot, + (void *) XtOffsetOf (shire_dir_config, bRequireAll), + OR_AUTHCFG, FLAG, "All require directives must match!"}, {NULL} }; +static const XMLCh Apache[] = +{ chLatin_A, chLatin_p, chLatin_a, chLatin_c, chLatin_h, chLatin_e, chNull }; +static const XMLCh apacheConfig[] = +{ chLatin_a, chLatin_p, chLatin_a, chLatin_c, chLatin_h, chLatin_e, + chLatin_C, chLatin_o, chLatin_n, chLatin_f, chLatin_i, chLatin_g, 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 }; + /* * shire_child_init() * Things to do when the child process is initialized. @@ -128,24 +141,49 @@ extern "C" void shire_child_init(server_rec* s, pool* p) { // Initialize runtime components. - ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s, - "shire_child_init() starting"); + ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s,"shire_child_init() starting"); if (g_Config) { - ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,s, - "shire_child_init(): already initialized!"); - exit (1); + ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,s,"shire_child_init(): already initialized!"); + exit(1); } try { - g_Config = &(ShibTargetConfig::init(SHIBTARGET_SHIRE, g_szSHIREConfig)); - } catch (...) { - ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s, - "shire_child_init() failed to initialize SHIB Target"); - exit (1); + g_Config=&ShibTargetConfig::getConfig(); + g_Config->setFeatures( + ShibTargetConfig::Listener | + ShibTargetConfig::Metadata | + ShibTargetConfig::AAP | + ShibTargetConfig::RequestMapper | + ShibTargetConfig::SHIREExtensions + ); + if (!g_Config->init(g_szSchemaDir,g_szSHIBConfig)) { + ap_log_error(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,s,"shire_child_init(): already initialized!"); + exit(1); + } + + // Access the implementation-specifics for whether to use old Apache config style... + IConfig* conf=g_Config->getINI(); + Locker locker(conf); + const IPropertySet* props=conf->getPropertySet("SHIRE"); + if (props) { + const DOMElement* impl=saml::XML::getFirstChildElement( + props->getElement(),ShibTargetConfig::SHIBTARGET_NS,Implementation + ); + if (impl && (impl=saml::XML::getFirstChildElement(impl,ShibTargetConfig::SHIBTARGET_NS,Apache))) { + const XMLCh* flag=impl->getAttributeNS(NULL,apacheConfig); + if (flag && (*flag==chDigit_1 || *flag==chLatin_t)) + g_bApacheConf=true; + } + } + } + catch (...) { + ap_log_error(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,s,"shire_child_init() failed to initialize SHIB Target"); + exit (1); } - ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s,"shire_child_init() done"); + ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s, + "shire_child_init() done, apacheConfig set to %s", g_bApacheConf ? "true" : "false"); } @@ -160,77 +198,28 @@ extern "C" void shire_child_exit(server_rec* s, pool* p) ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s,"shire_child_exit() done"); } -inline char hexchar(unsigned short s) -{ - return (s<=9) ? ('0' + s) : ('A' + s - 10); -} - -static char* url_encode(request_rec* r, const char* s) -{ - static char badchars[]="\"\\+<>#%{}|^~[]`;/?:@=&"; - char* ret=(char*)ap_palloc(r->pool,sizeof(char)*3*strlen(s)+1); - - unsigned long count=0; - for (; *s; s++) - { - if (strchr(badchars,*s)!=NULL || *s<=0x1F || *s>=0x7F) - { - ret[count++]='%'; - ret[count++]=hexchar(*s >> 4); - ret[count++]=hexchar(*s & 0x0F); - } - else - ret[count++]=*s; - } - ret[count++]=*s; - return ret; -} - -static const char* get_application_id(request_rec* r) -{ - ApplicationMapper mapper; - return ap_pstrdup(r->pool, - mapper->getApplicationFromParsedURL( - ap_http_method(r), ap_get_server_name(r), ap_get_server_port(r), r->unparsed_uri - ) - ); -} - -static const char* get_shire_location(request_rec* r, const char* target, const char* application_id) +static int shire_error_page(request_rec* r, const IApplication* app, const char* page, ShibMLP& mlp) { - string shire_location; - ShibINI& ini = g_Config->getINI(); + const IPropertySet* props=app->getPropertySet("Errors"); + if (props) { + pair p=props->getString(page); + if (p.first) { + ifstream infile(p.second); + if (!infile.fail()) { + const char* res = mlp.run(infile); + if (res) { + r->content_type = ap_psprintf(r->pool, "text/html"); + ap_send_http_header(r); + ap_rprintf(r, res); + return DONE; + } + } + } + } - if (!ini.get_tag (application_id, "shireURL", true, &shire_location)) { ap_log_rerror(APLOG_MARK,APLOG_ERR,r, - "shire_get_location() no shireURL configuration for %s", application_id); - return NULL; - } - - const char* shire = shire_location.c_str(); - - if (*shire != '/') - return ap_pstrdup(r->pool,shire); - - const char* colon=strchr(target,':'); - const char* slash=strchr(colon+3,'/'); - return ap_pstrcat(r->pool, ap_pstrndup(r->pool,target,slash-target), shire, NULL); -} - -static int shire_error_page(request_rec* r, const char* filename, ShibMLP& mlp) -{ - ifstream infile (filename); - if (!infile) { - ap_log_rerror(APLOG_MARK,APLOG_ERR,r, - "shire_error_page() cannot open %s", filename); - return SERVER_ERROR; - } - - string res = mlp.run(infile); - r->content_type = ap_psprintf(r->pool, "text/html"); - ap_send_http_header(r); - ap_rprintf(r, res.c_str()); - return DONE; + "shire_error_page() could not process shire error template for application %s",app->getId()); + return SERVER_ERROR; } extern "C" int shire_check_user(request_rec* r) @@ -238,30 +227,47 @@ extern "C" int shire_check_user(request_rec* r) ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_user: ENTER"); shire_dir_config* dc=(shire_dir_config*)ap_get_module_config(r->per_dir_config,&shire_module); + ostringstream threadid; + threadid << "[" << getpid() << "] shire" << '\0'; + saml::NDC ndc(threadid.str().c_str()); + // This will always be normalized, because Apache uses ap_get_server_name in this API call. const char* targeturl=ap_construct_url(r->pool,r->unparsed_uri,r); + + // We lock the configuration system for the duration. + IConfig* conf=g_Config->getINI(); + Locker locker(conf); - // Map request to application ID, which is the key for config lookup. - const char* application_id=get_application_id(r); + // Map request to application and content settings. + IRequestMapper* mapper=conf->getRequestMapper(); + Locker locker2(mapper); + IRequestMapper::Settings settings=mapper->getSettingsFromParsedURL( + ap_http_method(r), ap_get_server_name(r), ap_get_server_port(r), r->unparsed_uri + ); + pair 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) { + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r, + "shire_check_user: unable to map request to application session settings, check configuration"); + return SERVER_ERROR; + } - // Get unescaped location of this application's assertion consumer service. - const char* unescaped_shire = get_shire_location(r, targeturl, application_id); + // Declare SHIRE object for this request. + SHIRE shire(application); - if (strstr(targeturl,unescaped_shire)) { - ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r, - "shire_check_user: REQUEST FOR SHIRE! Maybe you did not configure the SHIRE Handler?"); - return SERVER_ERROR; - } - else { - // Regular access to arbitrary resource...check AuthType - const char *auth_type=ap_auth_type (r); - if (!auth_type) + // Get location of this application's assertion consumer service and see if this is it. + if (strstr(targeturl,shire.getShireURL(targeturl))) { + return shire_handler(r,application,sessionProps,shire); + } + + // Regular access to arbitrary resource...check AuthType + const char *auth_type=ap_auth_type(r); + if (!auth_type) return DECLINED; - if (strcasecmp(auth_type,"shibboleth")) - { - if (!strcasecmp(auth_type,"basic") && dc->bBasicHijack==1) - { + if (strcasecmp(auth_type,"shibboleth")) { + if (!strcasecmp(auth_type,"basic") && dc->bBasicHijack==1) { core_dir_config* conf= (core_dir_config*)ap_get_module_config(r->per_dir_config, ap_find_linked_module("http_core.c")); @@ -269,69 +275,35 @@ extern "C" int shire_check_user(request_rec* r) } else return DECLINED; - } - - // set the connection authtype - if (r->connection) - r->connection->ap_auth_type = "shibboleth"; - - // SSL check. - if (dc->bSSLOnly==1 && strcmp(ap_http_method(r),"https")) - { - ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"shire_check_user() blocked non-SSL access"); - return SERVER_ERROR; - } } - ostringstream threadid; - threadid << "[" << getpid() << "] shire" << '\0'; - saml::NDC ndc(threadid.str().c_str()); - - ShibINI& ini = g_Config->getINI(); - - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, - "shire_check_user() Shib check for %s", targeturl); - - - string tag; - bool has_tag = ini.get_tag (application_id, "checkIPAddress", true, &tag); - dc->config.checkIPAddress = (has_tag ? ShibINI::boolean (tag) : false); - - string shib_cookie; - if (!ini.get_tag(application_id, "cookieName", true, &shib_cookie)) { - ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r, - "shire_check_user: no cookieName configuration for %s", application_id); - return SERVER_ERROR; - } - - string wayfLocation; - if (!ini.get_tag(application_id, "wayfURL", true, &wayfLocation)) { - ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r, - "shire_check_user: no wayfURL configuration for %s", application_id); - return SERVER_ERROR; + pair requireSession = pair(false,false); + if (g_bApacheConf) { + // By default, we will require a session. + if (dc->bRequireSession!=0) + requireSession.second=true; } + else + requireSession = settings.first->getBool("requireSession"); - string shireError; - if (!ini.get_tag(application_id, "shireError", true, &shireError)) { - ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r, - "shire_check_user: no shireError configuration for %s", application_id); - return SERVER_ERROR; - } + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_user: session check for %s",targeturl); - SHIRE shire(dc->config, unescaped_shire); + pair shib_cookie=sessionProps->getString("cookieName"); + if (!shib_cookie.first) { + ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r, + "shire_check_user: no cookieName set for %s", application_id.second); + return SERVER_ERROR; + } // We're in charge, so check for cookie. const char* session_id=NULL; const char* cookies=ap_table_get(r->headers_in,"Cookie"); - if (cookies) - { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, - "shire_check_user() cookies found: %s",cookies); - if (session_id=strstr(cookies,shib_cookie.c_str())) - { + if (cookies) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_user: cookies found: %s",cookies); + if (session_id=strstr(cookies,shib_cookie.second)) { // Yep, we found a cookie -- pull it out (our session_id) - session_id+=strlen(shib_cookie.c_str()) + 1; /* Skip over the '=' */ + session_id+=strlen(shib_cookie.second) + 1; /* Skip over the '=' */ char* cookiebuf = ap_pstrdup(r->pool,session_id); char* cookieend = strchr(cookiebuf,';'); if (cookieend) @@ -340,287 +312,669 @@ extern "C" int shire_check_user(request_rec* r) } } - if (!session_id || !*session_id) - { - // No acceptable cookie. Redirect to WAYF. - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, - "shire_check_user() no cookie found -- redirecting to WAYF"); - char timebuf[16]; - sprintf(timebuf,"%u",time(NULL)); - char* wayf=ap_pstrcat(r->pool,wayfLocation.c_str(), - "?shire=",url_encode(r,unescaped_shire), - "&target=",url_encode(r,targeturl), - "&time=",timebuf, - "&providerId=",application_id,NULL); - ap_table_setn(r->headers_out,"Location",wayf); + if (!session_id || !*session_id) { + // If no session required, bail now. + if (!requireSession.second) + return DECLINED; + + // No acceptable cookie, and we require a session. Generate an AuthnRequest. + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_user: no cookie found -- redirecting to WAYF"); + ap_table_setn(r->headers_out,"Location",ap_pstrdup(r->pool,shire.getAuthnRequest(targeturl))); return REDIRECT; } - // Make sure this session is still valid + // Make sure this session is still valid. RPCError* status = NULL; - ShibMLP markupProcessor; - has_tag = ini.get_tag(application_id, "supportContact", true, &tag); - markupProcessor.insert("supportContact", has_tag ? tag : ""); - has_tag = ini.get_tag(application_id, "logoLocation", true, &tag); - markupProcessor.insert("logoLocation", has_tag ? tag : ""); + ShibMLP markupProcessor(application); markupProcessor.insert("requestURL", targeturl); try { - status = shire.sessionIsValid(session_id, r->connection->remote_ip,application_id); + status = shire.sessionIsValid(session_id, r->connection->remote_ip); } catch (ShibTargetException &e) { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_user(): %s", e.what()); - markupProcessor.insert ("errorType", "SHIRE Processing Error"); - markupProcessor.insert ("errorText", e.what()); - markupProcessor.insert ("errorDesc", "An error occurred while processing your request."); - return shire_error_page (r, shireError.c_str(), markupProcessor); + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"shire_check_user(): %s", e.what()); + markupProcessor.insert("errorType", "Session Processing Error"); + markupProcessor.insert("errorText", e.what()); + markupProcessor.insert("errorDesc", "An error occurred while processing your request."); + return shire_error_page(r, application, "shire", markupProcessor); } +#ifndef _DEBUG catch (...) { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_user(): caught unexpected error"); - markupProcessor.insert ("errorType", "SHIRE Processing Error"); - markupProcessor.insert ("errorText", "Unexpected Exception"); - markupProcessor.insert ("errorDesc", "An error occurred while processing your request."); - return shire_error_page (r, shireError.c_str(), markupProcessor); + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"shire_check_user(): caught unexpected error"); + markupProcessor.insert("errorType", "Session Processing Error"); + markupProcessor.insert("errorText", "Unexpected Exception"); + markupProcessor.insert("errorDesc", "An error occurred while processing your request."); + return shire_error_page(r, application, "shire", markupProcessor); } +#endif // Check the status if (status->isError()) { ap_log_rerror(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,r, - "shire_check_user() session invalid: %s", - status->getText()); - - if (status->isRetryable()) { - // Oops, session is invalid. Redirect to WAYF. - char timebuf[16]; - sprintf(timebuf,"%u",time(NULL)); - char* wayf=ap_pstrcat(r->pool,wayfLocation.c_str(), - "?shire=",url_encode(r,unescaped_shire), - "&target=",url_encode(r,targeturl), - "&time=",timebuf, - "&providerId=",application_id,NULL); - ap_table_setn(r->headers_out,"Location",wayf); + "shire_check_user() session invalid: %s", status->getText()); + // If no session required, bail now. + if (!requireSession.second) + return DECLINED; + else if (status->isRetryable()) { + // Oops, session is invalid. Generate AuthnRequest. + ap_table_setn(r->headers_out,"Location",ap_pstrdup(r->pool,shire.getAuthnRequest(targeturl))); delete status; return REDIRECT; } else { // return the error page to the user - markupProcessor.insert (*status); + markupProcessor.insert(*status); delete status; - return shire_error_page (r, shireError.c_str(), markupProcessor); + return shire_error_page(r, application, "shire", markupProcessor); } } - else { - delete status; - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_user() success"); - return OK; + + delete status; + // set the connection authtype + if (r->connection) + r->connection->ap_auth_type = "shibboleth"; + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_user: session successfully verified"); + + // This is code transferred in from mod_shibrm to export the attributes. + // We could even combine the isSessionValid/getAssertions API...? + + RM rm(application); + vector assertions; + SAMLAuthenticationStatement* sso_statement=NULL; + + try { + status = rm.getAssertions(session_id, r->connection->remote_ip, assertions, &sso_statement); + } + catch (ShibTargetException &e) { + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"shire_check_user(): %s", e.what()); + markupProcessor.insert("errorType", "Attribute Processing Error"); + markupProcessor.insert("errorText", e.what()); + markupProcessor.insert("errorDesc", "An error occurred while processing your request."); + return shire_error_page(r, application, "rm", markupProcessor); + } +#ifndef _DEBUG + catch (...) { + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"shire_check_user(): caught unexpected error"); + markupProcessor.insert("errorType", "Attribute Processing Error"); + markupProcessor.insert("errorText", "Unexpected Exception"); + markupProcessor.insert("errorDesc", "An error occurred while processing your request."); + return shire_error_page(r, application, "rm", markupProcessor); } +#endif - ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"shire_check_user() server error"); - return SERVER_ERROR; -} + if (status->isError()) { + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r, + "shire_check_user() getAssertions failed: %s", status->getText()); -extern "C" int shire_post_handler (request_rec* r) -{ - ostringstream threadid; - threadid << "[" << getpid() << "] shire" << '\0'; - saml::NDC ndc(threadid.str().c_str()); + markupProcessor.insert(*status); + delete status; + return shire_error_page(r, application, "rm", markupProcessor); + } + delete status; - ShibINI& ini = g_Config->getINI(); - ShibMLP markupProcessor; + // Do we have an access control plugin? + if (settings.second) { + Locker acllock(settings.second); + if (!settings.second->authorized(assertions)) { + for (int k = 0; k < assertions.size(); k++) + delete assertions[k]; + delete sso_statement; + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"shire_check_user(): access control provider denied access"); + return shire_error_page(r, application, "access", markupProcessor); + } + } - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_post_handler() ENTER"); + // Get the AAP providers, which contain the attribute policy info. + Iterator provs=application->getAAPProviders(); + + // Clear out the list of mapped attributes + while (provs.hasNext()) { + IAAP* aap=provs.next(); + aap->lock(); + try { + Iterator rules=aap->getAttributeRules(); + while (rules.hasNext()) { + const char* header=rules.next()->getHeader(); + if (header) + ap_table_unset(r->headers_in,header); + } + } + catch(...) { + aap->unlock(); + for (int k = 0; k < assertions.size(); k++) + delete assertions[k]; + delete sso_statement; + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r, + "shire_check_user(): caught unexpected error while clearing headers"); + markupProcessor.insert("errorType", "Attribute Processing Error"); + markupProcessor.insert("errorText", "Unexpected Exception"); + markupProcessor.insert("errorDesc", "An error occurred while processing your request."); + return shire_error_page(r, application, "rm", markupProcessor); + } + aap->unlock(); + } + provs.reset(); + + // Maybe export the first assertion. + ap_table_unset(r->headers_in,"Shib-Attributes"); + pair exp=pair(false,false); + if (g_bApacheConf && dc->bExportAssertion==1) + exp.second=exp.first=true; + else if (!g_bApacheConf) + exp=settings.first->getBool("exportAssertion"); + if (exp.first && exp.second && assertions.size()) { + string assertion; + RM::serialize(*(assertions[0]), assertion); + ap_table_set(r->headers_in,"Shib-Attributes", assertion.c_str()); + } - // This will always be normalized, because Apache uses ap_get_server_name in this API call. - const char* targeturl = ap_construct_url(r->pool,r->unparsed_uri,r); - - // Map request to application ID, which is the key for config lookup. - const char* application_id = get_application_id(r); + // Export the SAML AuthnMethod and the origin site name. + ap_table_unset(r->headers_in,"Shib-Origin-Site"); + ap_table_unset(r->headers_in,"Shib-Authentication-Method"); + if (sso_statement) { + auto_ptr_char os(sso_statement->getSubject()->getNameQualifier()); + auto_ptr_char am(sso_statement->getAuthMethod()); + ap_table_set(r->headers_in,"Shib-Origin-Site", os.get()); + ap_table_set(r->headers_in,"Shib-Authentication-Method", am.get()); + } - // The SHIRE URL is the current request URL, by definition... - const char* unescaped_shire = targeturl; - - string tag; - bool has_tag = ini.get_tag(application_id, "checkIPAddress", true, &tag); - SHIREConfig config; - config.checkIPAddress = (has_tag ? ShibINI::boolean(tag) : false); - - string shib_cookie; - if (! ini.get_tag(application_id, "cookieName", true, &shib_cookie)) { - ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r, - "shire_check_user: no cookieName configuration for %s", application_id); - return SERVER_ERROR; - } + ap_table_unset(r->headers_in,"Shib-Application-ID"); + ap_table_set(r->headers_in,"Shib-Application-ID",application_id.second); + + // Export the attributes. + Iterator a_iter(assertions); + while (a_iter.hasNext()) { + SAMLAssertion* assert=a_iter.next(); + Iterator statements=assert->getStatements(); + while (statements.hasNext()) { + SAMLAttributeStatement* astate=dynamic_cast(statements.next()); + if (!astate) + continue; + Iterator attrs=astate->getAttributes(); + while (attrs.hasNext()) { + SAMLAttribute* attr=attrs.next(); + + // Are we supposed to export it? + AAP wrapper(provs,attr->getName(),attr->getNamespace()); + if (wrapper.fail()) + continue; + + Iterator vals=attr->getSingleByteValues(); + if (!strcmp(wrapper->getHeader(),"REMOTE_USER") && vals.hasNext()) + r->connection->user=ap_pstrdup(r->pool,vals.next().c_str()); + else { + int it=0; + char* header = (char*)ap_table_get(r->headers_in, wrapper->getHeader()); + if (header) { + header=ap_pstrdup(r->pool, header); + it++; + } + else + header = ap_pstrdup(r->pool, ""); + for (; vals.hasNext(); it++) { + string value = vals.next(); + for (string::size_type pos = value.find_first_of(";", string::size_type(0)); + pos != string::npos; + pos = value.find_first_of(";", pos)) { + value.insert(pos, "\\"); + pos += 2; + } + header=ap_pstrcat(r->pool, header, (it ? ";" : ""), value.c_str(), NULL); + } + ap_table_setn(r->headers_in, wrapper->getHeader(), header); + } + } + } + } - string wayfLocation; - if (! ini.get_tag(application_id, "wayfURL", true, &wayfLocation)) { - ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r, - "shire_check_user: no wayfURL configuration for %s", application_id); - return SERVER_ERROR; - } + // clean up memory + for (int k = 0; k < assertions.size(); k++) + delete assertions[k]; + delete sso_statement; - string shireError; - if (! ini.get_tag(application_id, "shireError", true, &shireError)) { - ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r, - "shire_check_user: no shireError configuration for %s", application_id); - return SERVER_ERROR; - } + return OK; +} - has_tag = ini.get_tag(application_id, "supportContact", true, &tag); - markupProcessor.insert("supportContact", has_tag ? tag : ""); - has_tag = ini.get_tag(application_id, "logoLocation", true, &tag); - markupProcessor.insert("logoLocation", has_tag ? tag : ""); - markupProcessor.insert("requestURL", targeturl); - - SHIRE shire(config, unescaped_shire); +extern "C" int shire_post_handler(request_rec* r) +{ + ostringstream threadid; + threadid << "[" << getpid() << "] shire_post_handler" << '\0'; + saml::NDC ndc(threadid.str().c_str()); - // Process SHIRE POST + // We lock the configuration system for the duration. + IConfig* conf=g_Config->getINI(); + Locker locker(conf); + + // Map request to application and content settings. + IRequestMapper* mapper=conf->getRequestMapper(); + Locker locker2(mapper); + IRequestMapper::Settings settings=mapper->getSettingsFromParsedURL( + ap_http_method(r), ap_get_server_name(r), ap_get_server_port(r), r->unparsed_uri + ); + pair 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) { + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r, + "shire_post_handler: unable to map request to application session settings, check configuration"); + return SERVER_ERROR; + } + + // Declare SHIRE object for this request. + SHIRE shire(application); + + return shire_handler(r, application, sessionProps, shire); +} - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, - "shire_post_handler() Beginning SHIRE POST processing"); +int shire_handler(request_rec* r, const IApplication* application, const IPropertySet* sessionProps, SHIRE& shire) +{ + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_handler() ENTER"); + + // Prime the pump... + const char* targeturl = ap_construct_url(r->pool,r->unparsed_uri,r); + shire.getShireURL(targeturl); + + pair shib_cookie=sessionProps->getString("cookieName"); + pair shib_cookie_props=sessionProps->getString("cookieProps"); + if (!shib_cookie.first) { + ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r, + "shire_handler: no cookieName set for %s", application->getId()); + return SERVER_ERROR; + } + + ShibMLP markupProcessor(application); + markupProcessor.insert("requestURL", targeturl); + + // Process SHIRE request + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, "shire_handler() Beginning SHIRE processing"); + + try { + pair shireSSL=sessionProps->getBool("shireSSL"); - try { - string sslonly; - if (!ini.get_tag(application_id, "shireSSLOnly", true, &sslonly)) - ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r, - "shire_post_handler: no shireSSLOnly configuration"); + // Make sure this is SSL, if it should be + if ((!shireSSL.first || shireSSL.second) && strcmp(ap_http_method(r),"https")) + throw ShibTargetException(SHIBRPC_OK, "blocked non-SSL access to session creation service"); - // Make sure this is SSL, if it should be - if (ShibINI::boolean(sslonly) && strcmp(ap_http_method(r),"https")) - throw ShibTargetException(SHIBRPC_OK, "blocked non-SSL access to SHIRE POST processor"); - - // Make sure this is a POST - if (strcasecmp (r->method, "POST")) - throw ShibTargetException(SHIBRPC_OK, "blocked non-POST to SHIRE POST processor"); - - // Sure sure this POST is an appropriate content type - const char *ct = ap_table_get (r->headers_in, "Content-type"); - if (!ct || strcasecmp (ct, "application/x-www-form-urlencoded")) - throw ShibTargetException (SHIBRPC_OK, - ap_psprintf(r->pool, - "blocked bad content-type to SHIRE POST processor: %s", - (ct ? ct : ""))); - - // Make sure the "bytes sent" is a reasonable number - if (r->bytes_sent > 1024*1024) // 1MB? - throw ShibTargetException (SHIBRPC_OK, - "blocked too-large a post to SHIRE POST processor"); - - // Read the posted data - ApacheRequest *ap_req = ApacheRequest_new(r); - int err = ApacheRequest_parse(ap_req); - if (err != OK) - throw ShibTargetException (SHIBRPC_OK, - ap_psprintf(r->pool, - "ApacheRequest_parse() failed with %d.", err)); + // If this is a GET, we manufacture an AuthnRequest. + if (!strcasecmp(r->method,"GET")) { + const char* areq=r->args ? shire.getLazyAuthnRequest(r->args) : NULL; + if (!areq) + throw ShibTargetException(SHIBRPC_OK, "malformed arguments to request a new session"); + ap_table_setn(r->headers_out, "Location", ap_pstrdup(r->pool,areq)); + return REDIRECT; + } + else if (strcasecmp(r->method,"POST")) { + throw ShibTargetException(SHIBRPC_OK, "blocked non-POST to SHIRE POST processor"); + } + + // Sure sure this POST is an appropriate content type + const char *ct = ap_table_get(r->headers_in, "Content-type"); + if (!ct || strcasecmp(ct, "application/x-www-form-urlencoded")) + throw ShibTargetException(SHIBRPC_OK, + ap_psprintf(r->pool, "blocked bad content-type to SHIRE POST processor: %s", (ct ? ct : ""))); + + // Read the posted data + if (ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)) + throw ShibTargetException(SHIBRPC_OK, "CGI setup_client_block failed"); + if (!ap_should_client_block(r)) + throw ShibTargetException(SHIBRPC_OK, "CGI should_client_block failed"); + if (r->remaining > 1024*1024) + throw ShibTargetException (SHIBRPC_OK, "CGI length too long..."); + string cgistr; + char buff[HUGE_STRING_LEN]; + ap_hard_timeout("mod_shire", r); + memset(buff, 0, sizeof(buff)); + while (ap_get_client_block(r, buff, sizeof(buff)-1) > 0) { + cgistr += buff; + memset(buff, 0, sizeof(buff)); + } + ap_kill_timeout(r); + // Parse the submission. + pair elements=shire.getFormSubmission(cgistr.c_str()); + + // Make sure the SAML Response parameter exists + if (!elements.first || !*elements.first) + throw ShibTargetException(SHIBRPC_OK, "SHIRE POST failed to find SAMLResponse form element"); + + // Make sure the target parameter exists + if (!elements.second || !*elements.second) + throw ShibTargetException(SHIBRPC_OK, "SHIRE POST failed to find TARGET form element"); - // Make sure the target parameter exists - const char *target = ApacheRequest_param(ap_req, "TARGET"); - if (!target || *target == '\0') - // invalid post - throw ShibTargetException (SHIBRPC_OK, - "SHIRE POST failed to find TARGET"); - - // Make sure the SAML Response parameter exists - const char *post = ApacheRequest_param(ap_req, "SAMLResponse"); - if (!post || *post == '\0') - // invalid post - throw ShibTargetException (SHIBRPC_OK, - "SHIRE POST failed to find SAMLResponse"); - - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, - "shire_post_handler() Processing POST for target: %s", target); - - // process the post - string cookie; - RPCError* status = shire.sessionCreate(post, r->connection->remote_ip, application_id, cookie); + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, + "shire_handler() Processing POST for target: %s", elements.second); - if (status->isError()) { - ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r, - "shire_post_handler() POST process failed (%d): %s", - status->getCode(), status->getText()); - - if (status->isRetryable()) { - ap_log_rerror(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,r, - "shire_post_handler() Retrying POST by redirecting to WAYF"); - - char timebuf[16]; - sprintf(timebuf,"%u",time(NULL)); - char* wayf=ap_pstrcat(r->pool,wayfLocation.c_str(), - "?shire=",url_encode(r,unescaped_shire), - "&target=",url_encode(r,targeturl), - "&time=",timebuf, - "&providerId=",application_id,NULL); - ap_table_setn(r->headers_out,"Location",wayf); + // process the post + string cookie; + RPCError* status = shire.sessionCreate(elements.first, r->connection->remote_ip, cookie); + + if (status->isError()) { + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r, + "shire_handler() POST process failed (%d): %s", status->getCode(), status->getText()); + + if (status->isRetryable()) { + delete status; + ap_log_rerror(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,r, + "shire_handler() retryable error, generating new AuthnRequest"); + ap_table_setn(r->headers_out,"Location",ap_pstrdup(r->pool,shire.getAuthnRequest(elements.second))); + return REDIRECT; + } + + // return this error to the user. + markupProcessor.insert(*status); + delete status; + return shire_error_page(r, application, "shire", markupProcessor); + } delete status; + + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, + "shire_handler() POST process succeeded. New session: %s", cookie.c_str()); + + // We've got a good session, set the cookie... + char* val = ap_psprintf(r->pool,"%s=%s%s",shib_cookie.second,cookie.c_str(), + shib_cookie_props.first ? shib_cookie_props.second : ""); + ap_table_setn(r->err_headers_out, "Set-Cookie", val); + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, "shire_handler() setting cookie: %s", val); + + // ... and redirect to the target + ap_table_setn(r->headers_out, "Location", ap_pstrdup(r->pool,elements.second)); return REDIRECT; } + catch (ShibTargetException &e) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, "shire_handler() caught exception: %s", e.what()); + markupProcessor.insert("errorType", "Session Creation Service Error"); + markupProcessor.insert("errorText", e.what()); + markupProcessor.insert("errorDesc", "An error occurred while processing your request."); + return shire_error_page(r, application, "shire", markupProcessor); + } +#ifndef _DEBUG + catch (...) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_handler(): unexpected exception"); + markupProcessor.insert("errorType", "Session Creation Service Error"); + markupProcessor.insert("errorText", "Unknown Exception"); + markupProcessor.insert("errorDesc", "An error occurred while processing your request."); + return shire_error_page(r, application, "shire", markupProcessor); + } +#endif + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"shire_handler() server error"); + return SERVER_ERROR; +} - // return this error to the user. - markupProcessor.insert (*status); - delete status; - return shire_error_page (r, shireError.c_str(), markupProcessor); +static table* groups_for_user(request_rec* r, const char* user, char* grpfile) +{ + configfile_t* f; + table* grps=ap_make_table(r->pool,15); + char l[MAX_STRING_LEN]; + const char *group_name, *ll, *w; + + if (!(f=ap_pcfg_openfile(r->pool,grpfile))) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG,r,"groups_for_user() could not open group file: %s\n",grpfile); + return NULL; } - delete status; - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, - "shire_post_handler() POST process succeeded. New cookie: %s", - cookie.c_str()); - - // We've got a good session, set the cookie... - char * domain = NULL; - char * new_cookie = ap_psprintf(r->pool, "%s=%s; path=/%s%s", - shib_cookie.c_str(), - cookie.c_str(), - (domain ? "; domain=" : ""), - (domain ? domain : "")); + pool* sp=ap_make_sub_pool(r->pool); + + while (!(ap_cfg_getline(l,MAX_STRING_LEN,f))) { + if ((*l=='#') || (!*l)) + continue; + ll = l; + ap_clear_pool(sp); + + group_name=ap_getword(sp,&ll,':'); + + while (*ll) { + w=ap_getword_conf(sp,&ll); + if (!strcmp(w,user)) { + ap_table_setn(grps,ap_pstrdup(r->pool,group_name),"in"); + break; + } + } + } + ap_cfg_closefile(f); + ap_destroy_pool(sp); + return grps; +} + +extern "C" int shire_check_auth(request_rec* r) +{ + shire_dir_config* dc= + (shire_dir_config*)ap_get_module_config(r->per_dir_config,&shire_module); + + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_auth() executing"); + + // Regular access to arbitrary resource...check AuthType + const char* auth_type=ap_auth_type(r); + if (!auth_type || strcasecmp(auth_type,"shibboleth")) + return DECLINED; + + ostringstream threadid; + threadid << "[" << getpid() << "] shibrm" << '\0'; + saml::NDC ndc(threadid.str().c_str()); + + // We lock the configuration system for the duration. + IConfig* conf=g_Config->getINI(); + Locker locker(conf); - ap_table_setn(r->err_headers_out, "Set-Cookie", new_cookie); - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, - "shire_post_handler() Set cookie: %s", new_cookie); - - // ... and redirect to the target - char* redir=ap_pstrcat(r->pool,url_encode(r,target),NULL); - ap_table_setn(r->headers_out, "Location", target); - return REDIRECT; - - } catch (ShibTargetException &e) { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, - "shire_post_handler(): %s", e.what()); - - markupProcessor.insert ("errorType", "SHIRE Processing Error"); - markupProcessor.insert ("errorText", e.what()); - markupProcessor.insert ("errorDesc", "An error occurred while processing your request."); - return shire_error_page (r, shireError.c_str(), markupProcessor); - } - catch (...) { - ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_post_handler(): unexpected exception"); - - markupProcessor.insert ("errorType", "SHIRE Processing Error"); - markupProcessor.insert ("errorText", "Unexpected Exception"); - markupProcessor.insert ("errorDesc", "An error occurred while processing your request."); - return shire_error_page (r, shireError.c_str(), markupProcessor); - } - - ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"shire_post_handler() server error"); - return SERVER_ERROR; + const char* application_id=ap_table_get(r->headers_in,"Shib-Application-ID"); + if (!application_id) { + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r, + "shire_check_auth: Shib-Application-ID header not found in request"); + return FORBIDDEN; + } + + const IApplication* application=conf->getApplication(application_id); + if (!application) { + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r, + "shire_check_auth: unable to map request to application settings, check configuration"); + return SERVER_ERROR; + } + + // mod_auth clone + + int m=r->method_number; + bool method_restricted=false; + const char *t, *w; + + const array_header* reqs_arr=ap_requires(r); + if (!reqs_arr) + return OK; + + require_line* reqs=(require_line*)reqs_arr->elts; + + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"REQUIRE nelts: %d", reqs_arr->nelts); + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"REQUIRE all: %d", dc->bRequireAll); + + vector auth_OK(reqs_arr->nelts,false); + +#define SHIB_AP_CHECK_IS_OK { \ + if (dc->bRequireAll < 1) \ + return OK; \ + auth_OK[x] = true; \ + continue; \ } + for (int x=0; xnelts; x++) { + auth_OK[x] = false; + if (!(reqs[x].method_mask & (1 << m))) + continue; + method_restricted=true; + + t = reqs[x].requirement; + w = ap_getword_white(r->pool, &t); + + if (!strcmp(w,"valid-user")) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_auth() accepting valid-user"); + SHIB_AP_CHECK_IS_OK; + } + else if (!strcmp(w,"user") && r->connection->user) { + bool regexp=false; + while (*t) { + w=ap_getword_conf(r->pool,&t); + if (*w=='~') { + regexp=true; + continue; + } + + if (regexp) { + try { + // To do regex matching, we have to convert from UTF-8. + auto_ptr trans(fromUTF8(w)); + RegularExpression re(trans.get()); + auto_ptr trans2(fromUTF8(r->connection->user)); + if (re.matches(trans2.get())) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_auth() accepting user: %s",w); + SHIB_AP_CHECK_IS_OK; + } + } + catch (XMLException& ex) { + auto_ptr_char tmp(ex.getMessage()); + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r, + "shire_check_auth caught exception while parsing regular expression (%s): %s",w,tmp.get()); + } + } + else if (!strcmp(r->connection->user,w)) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_auth() accepting user: %s",w); + SHIB_AP_CHECK_IS_OK; + } + } + } + else if (!strcmp(w,"group")) { + table* grpstatus=NULL; + if (dc->szAuthGrpFile && r->connection->user) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_auth() using groups file: %s\n",dc->szAuthGrpFile); + grpstatus=groups_for_user(r,r->connection->user,dc->szAuthGrpFile); + } + if (!grpstatus) + return DECLINED; + + while (*t) { + w=ap_getword_conf(r->pool,&t); + if (ap_table_get(grpstatus,w)) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_auth() accepting group: %s",w); + SHIB_AP_CHECK_IS_OK; + } + } + } + else { + Iterator provs=application->getAAPProviders(); + AAP wrapper(provs,w); + if (wrapper.fail()) { + ap_log_rerror(APLOG_MARK,APLOG_WARNING|APLOG_NOERRNO,r, + "shire_check_auth() didn't recognize require rule: %s\n",w); + continue; + } + + bool regexp=false; + const char* vals=ap_table_get(r->headers_in,wrapper->getHeader()); + while (*t && vals) { + w=ap_getword_conf(r->pool,&t); + if (*w=='~') { + regexp=true; + continue; + } + + try { + auto_ptr re; + if (regexp) { + delete re.release(); + auto_ptr trans(fromUTF8(w)); + auto_ptr temp(new RegularExpression(trans.get())); + re=temp; + } + + string vals_str(vals); + int j = 0; + for (int i = 0; i < vals_str.length(); i++) { + if (vals_str.at(i) == ';') { + if (i == 0) { + ap_log_rerror(APLOG_MARK,APLOG_WARNING|APLOG_NOERRNO,r, + "shire_check_auth() invalid header encoding %s: starts with semicolon", vals); + return SERVER_ERROR; + } + + if (vals_str.at(i-1) == '\\') { + vals_str.erase(i-1, 1); + i--; + continue; + } + + string val = vals_str.substr(j, i-j); + j = i+1; + if (regexp) { + auto_ptr trans(fromUTF8(val.c_str())); + if (re->matches(trans.get())) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, + "shire_check_auth() expecting %s, got %s: authorization granted", w, val.c_str()); + SHIB_AP_CHECK_IS_OK; + } + } + else if (val==w) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, + "shire_check_auth() expecting %s, got %s: authorization granted", w, val.c_str()); + SHIB_AP_CHECK_IS_OK; + } + else { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, + "shire_check_auth() expecting %s, got %s: authorization not granted", w, val.c_str()); + } + } + } + + string val = vals_str.substr(j, vals_str.length()-j); + if (regexp) { + auto_ptr trans(fromUTF8(val.c_str())); + if (re->matches(trans.get())) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, + "shire_check_auth() expecting %s, got %s: authorization granted", w, val.c_str()); + SHIB_AP_CHECK_IS_OK; + } + } + else if (val==w) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, + "shire_check_auth() expecting %s, got %s: authorization granted", w, val.c_str()); + SHIB_AP_CHECK_IS_OK; + } + else { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r, + "shire_check_auth() expecting %s, got %s: authorization not granted", w, val.c_str()); + } + } + catch (XMLException& ex) { + auto_ptr_char tmp(ex.getMessage()); + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r, + "shire_check_auth caught exception while parsing regular expression (%s): %s",w,tmp.get()); + } + } + } + } + + // check if all require directives are true + bool auth_all_OK = true; + for (int i= 0; inelts; i++) { + auth_all_OK &= auth_OK[i]; + } + if (auth_all_OK) + return OK; + + if (!method_restricted) + return OK; + + ShibMLP markupProcessor(application); + markupProcessor.insert("requestURL", ap_construct_url(r->pool,r->unparsed_uri,r)); + return shire_error_page(r, application, "access", markupProcessor); +} + + extern "C"{ handler_rec shire_handlers[] = { { "shib-shire-post", shire_post_handler }, { NULL } }; -extern "C" void mod_shire_init (server_rec*r, pool* p) -{ - ShibTargetConfig::preinit(); -} - module MODULE_VAR_EXPORT shire_module = { STANDARD_MODULE_STUFF, - mod_shire_init, /* initializer */ + NULL, /* initializer */ create_shire_dir_config, /* dir config creater */ merge_shire_dir_config, /* dir merger --- default is to override */ NULL, /* server config */ @@ -628,8 +982,8 @@ module MODULE_VAR_EXPORT shire_module = { shire_cmds, /* command table */ shire_handlers, /* handlers */ NULL, /* filename translation */ - shire_check_user, /* check_user_id */ - NULL, /* check auth */ + shire_check_user, /* check_user_id */ + shire_check_auth, /* check auth */ NULL, /* check access */ NULL, /* type_checker */ NULL, /* fixups */ diff --git a/mod_shire/mod_shire.dsp b/mod_shire/mod_shire.dsp index 63fb8ed..f40ead3 100644 --- a/mod_shire/mod_shire.dsp +++ b/mod_shire/mod_shire.dsp @@ -43,7 +43,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MOD_SHIRE_EXPORTS" /YX /FD /c -# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I "..\oncrpc" /I ".." /I "..\..\..\opensaml\c" /I "\Apache\include" /I "\libapreq-1.3\include" /D "NDEBUG" /D "_USRDLL" /D "MOD_SHIRE_EXPORTS" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "EAPI" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I "..\oncrpc" /I ".." /I "..\..\..\opensaml\c" /I "\Apache\include" /D "NDEBUG" /D "_USRDLL" /D "MOD_SHIRE_EXPORTS" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "EAPI" /YX /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" @@ -53,7 +53,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # 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 /nologo /dll /machine:I386 -# ADD LINK32 log4cpp.lib xerces-c_2.lib libapreq.lib ApacheCore.lib saml_4.lib /nologo /dll /machine:I386 /libpath:"../../../opensaml/c/saml/Release" /libpath:"\Apache\libexec" /libpath:"\libapreq-1.3\c\Release" +# ADD LINK32 log4cpp.lib xerces-c_2.lib saml_4.lib ApacheCore.lib /nologo /dll /machine:I386 /libpath:"../../../opensaml/c/saml/Release" /libpath:"\Apache\libexec" !ELSEIF "$(CFG)" == "mod_shire - Win32 Debug" @@ -69,7 +69,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MOD_SHIRE_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /ZI /Od /I "..\oncrpc" /I ".." /I "..\..\..\opensaml\c" /I "\Apache\include" /I "\libapreq-1.3\include" /D "_DEBUG" /D "_AFXDLL" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "EAPI" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /ZI /Od /I "..\oncrpc" /I ".." /I "..\..\..\opensaml\c" /I "\Apache\include" /D "_DEBUG" /D "_AFXDLL" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "EAPI" /FR /YX /FD /GZ /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" @@ -79,7 +79,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # 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 /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 log4cppD.lib xerces-c_2D.lib ApacheCore.lib libapreq.lib saml_4D.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /libpath:"../../../opensaml/c/saml/Debug" /libpath:"\Apache\libexec" /libpath:"\libapreq-1.3\c\Debug" +# ADD LINK32 log4cppD.lib xerces-c_2D.lib saml_4D.lib ApacheCore.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /libpath:"../../../opensaml/c/saml/Debug" /libpath:"\Apache\libexec" !ENDIF