From 5e9b0a9ccf79078da7e98c8a21cdd245b939dc42 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Mon, 4 Jun 2007 13:32:08 +0000 Subject: [PATCH] Port up spoof checking --- apache/mod_apache.cpp | 57 +++++++--- configs/Makefile.am | 2 - configs/sessionError.html | 12 +-- configs/shibboleth.xml.in | 1 - schemas/shibboleth-2.0-native-sp-config.xsd | 159 ++++++++++++++-------------- shibsp/SPRequest.h | 5 +- shibsp/ServiceProvider.cpp | 16 +-- shibsp/impl/XMLServiceProvider.cpp | 54 +++++++--- 8 files changed, 178 insertions(+), 128 deletions(-) diff --git a/apache/mod_apache.cpp b/apache/mod_apache.cpp index 2d77272..36a26ea 100644 --- a/apache/mod_apache.cpp +++ b/apache/mod_apache.cpp @@ -14,12 +14,10 @@ * limitations under the License. */ -/* - * mod_apache.cpp -- the core Apache Module code - * - * Created by: Derek Atkins - * - * $Id$ +/** + * mod_apache.cpp + * + * Apache module implementation */ #define SHIBSP_LITE @@ -63,9 +61,9 @@ #define CORE_PRIVATE #include #include +#include #ifndef SHIB_APACHE_13 -#include #include #include #include @@ -91,6 +89,7 @@ namespace { char* g_szSchemaDir = SHIBSP_SCHEMAS; SPConfig* g_Config = NULL; string g_unsetHeaderValue; + bool g_checkSpoofing = true; static const char* g_UserDataKey = "_shib_check_user_"; static const XMLCh path[] = UNICODE_LITERAL_4(p,a,t,h); static const XMLCh validate[] = UNICODE_LITERAL_8(v,a,l,i,d,a,t,e); @@ -273,6 +272,7 @@ class ShibTargetApache : public AbstractSPRequest mutable string m_body; mutable bool m_gotBody; mutable vector m_certs; + set m_allhttp; public: request_rec* m_req; @@ -387,14 +387,40 @@ public: #endif return m_body.c_str(); } - void clearHeader(const char* name) { + void clearHeader(const char* rawname, const char* cginame) { if (m_dc->bUseEnvVars!=0) { // ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(m_req), "shib_clear_header: env\n"); - if (m_rc && m_rc->env) ap_table_unset(m_rc->env, name); + if (m_rc && m_rc->env) ap_table_unset(m_rc->env, rawname); } else { // ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(m_req), "shib_clear_header: hdr\n"); - ap_table_unset(m_req->headers_in, name); - ap_table_set(m_req->headers_in, name, g_unsetHeaderValue.c_str()); + if (g_checkSpoofing && ap_is_initial_req(m_req)) { + if (m_allhttp.empty()) { + // First time, so populate set with "CGI" versions of client-supplied headers. +#ifdef SHIB_APACHE_13 + array_header *hdrs_arr = ap_table_elts(m_req->headers_in); + table_entry *hdrs = (table_entry *) hdrs_arr->elts; +#else + const apr_array_header_t *hdrs_arr = apr_table_elts(m_req->headers_in); + const apr_table_entry_t *hdrs = (const apr_table_entry_t *) hdrs_arr->elts; +#endif + for (int i = 0; i < hdrs_arr->nelts; ++i) { + if (!hdrs[i].key) + continue; + string cgiversion("HTTP_"); + const char* pch = hdrs[i].key; + while (*pch) { + cgiversion += (isalnum(*pch) ? toupper(*pch) : '_'); + pch++; + } + m_allhttp.insert(cgiversion); + } + } + + if (m_allhttp.count(cginame) > 0) + throw opensaml::SecurityPolicyException("Attempt to spoof header ($1) was detected.", params(1, rawname)); + } + ap_table_unset(m_req->headers_in, rawname); + ap_table_set(m_req->headers_in, rawname, g_unsetHeaderValue.c_str()); } } void setHeader(const char* name, const char* value) { @@ -1122,6 +1148,9 @@ extern "C" void shib_child_init(apr_pool_t* p, server_rec* s) pair unsetValue=props->getString("unsetHeaderValue"); if (unsetValue.first) g_unsetHeaderValue = unsetValue.second; + pair checkSpoofing=props->getBool("checkSpoofing"); + if (checkSpoofing.first && !checkSpoofing.second) + g_checkSpoofing = false; } // Set the cleanup handler @@ -1326,8 +1355,8 @@ static command_rec shib_cmds[] = { (void *) offsetof (shib_dir_config, szRedirectToSSL), OR_AUTHCFG, "Redirect non-SSL requests to designated port"), AP_INIT_TAKE1("AuthGroupFile", (config_fn_t)shib_ap_set_file_slot, - (void *) offsetof (shib_dir_config, szAuthGrpFile), - OR_AUTHCFG, "Text file containing group names and member user IDs"), + (void *) offsetof (shib_dir_config, szAuthGrpFile), + OR_AUTHCFG, "Text file containing group names and member user IDs"), AP_INIT_FLAG("ShibRequireAll", (config_fn_t)ap_set_flag_slot, (void *) offsetof (shib_dir_config, bRequireAll), OR_AUTHCFG, "All require directives must match"), @@ -1349,7 +1378,7 @@ module AP_MODULE_DECLARE_DATA mod_shib = { }; #else -#error "undefined APACHE version" +#error "unsupported Apache version" #endif } diff --git a/configs/Makefile.am b/configs/Makefile.am index b59f561..790b7bf 100644 --- a/configs/Makefile.am +++ b/configs/Makefile.am @@ -31,7 +31,6 @@ CONFIGFILES = \ console.logger \ syslog.logger \ accessError.html \ - rmError.html \ sessionError.html \ metadataError.html \ bindingTemplate.html \ @@ -133,7 +132,6 @@ EXTRA_DIST = \ console.logger \ syslog.logger \ accessError.html \ - rmError.html \ sessionError.html \ metadataError.html \ sslError.html \ diff --git a/configs/sessionError.html b/configs/sessionError.html index d9f4485..3124317 100644 --- a/configs/sessionError.html +++ b/configs/sessionError.html @@ -7,25 +7,25 @@ - Session Creation Failure + <shibmlp errorType/>
Logo -

Session Creation Failure

+

-

The inter-institutional access system was unable to successfully build a -login session for you at

+

The inter-institutional access system encountered an error at

To report this problem, please contact the site administrator at .

Please include the following message in any email:

-

Session creation failure at ()

-

+

at ()

+ +

diff --git a/configs/shibboleth.xml.in b/configs/shibboleth.xml.in index b78440a..fa73946 100644 --- a/configs/shibboleth.xml.in +++ b/configs/shibboleth.xml.in @@ -170,7 +170,6 @@ --> - 2.0 schema for XML-based configuration of Shibboleth Native SP instances. - First appearing in Shibboleth 2.0 release. - - + 2.0 schema for XML-based configuration of Shibboleth Native SP instances. + First appearing in Shibboleth 2.0 release. + + - - + + - + @@ -44,20 +44,20 @@ - - - Root of configuration - - - - - - - - - - - + + + Root of configuration + + + + + + + + + + + @@ -121,26 +121,26 @@ - + Ties ReplayCache to a custom StorageService - + - + - + Customizes an ArtifactMap - - - + + + - + @@ -148,30 +148,30 @@ Container for shibd out-of-process configuration - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - + + + + @@ -184,22 +184,23 @@ - - + + - - - - - - - - - - - - - + + + + + + + + + + + + + + @@ -350,8 +351,8 @@ - - + + @@ -407,7 +408,7 @@ - + @@ -437,10 +438,10 @@ - - - Used to reference Policy elements from profile endpoints. - + + + Used to reference Policy elements from profile endpoints. + @@ -515,7 +516,7 @@ - + @@ -526,7 +527,7 @@ - + Container for specifying sets of policy rules to apply to incoming messages @@ -537,9 +538,9 @@ Specifies a set of SecurityPolicyRule plugins - - - + + + diff --git a/shibsp/SPRequest.h b/shibsp/SPRequest.h index c76eff9..a0b9ac4 100644 --- a/shibsp/SPRequest.h +++ b/shibsp/SPRequest.h @@ -111,9 +111,10 @@ namespace shibsp { /** * Ensures no value exists for a request header. * - * @param name name of header to clear + * @param rawname raw name of header to clear + * @param cginame CGI-equivalent name of header */ - virtual void clearHeader(const char* name)=0; + virtual void clearHeader(const char* rawname, const char* cginame)=0; /** * Sets a value for a request header. diff --git a/shibsp/ServiceProvider.cpp b/shibsp/ServiceProvider.cpp index 66f125c..3a4bb6d 100644 --- a/shibsp/ServiceProvider.cpp +++ b/shibsp/ServiceProvider.cpp @@ -87,12 +87,12 @@ namespace shibsp { } void SHIBSP_DLLLOCAL clearHeaders(SPRequest& request) { - request.clearHeader("Shib-Identity-Provider"); - request.clearHeader("Shib-Authentication-Method"); - request.clearHeader("Shib-AuthnContext-Class"); - request.clearHeader("Shib-AuthnContext-Decl"); - request.clearHeader("Shib-Attributes"); - request.clearHeader("Shib-Assertion-Count"); + request.clearHeader("Shib-Identity-Provider", "HTTP_SHIB_IDENTITY_PROVIDER"); + request.clearHeader("Shib-Authentication-Method", "HTTP_SHIB_AUTHENTICATION_METHOD"); + request.clearHeader("Shib-AuthnContext-Class", "HTTP_SHIB_AUTHNCONTEXT_CLASS"); + request.clearHeader("Shib-AuthnContext-Decl", "HTTP_SHIB_AUTHNCONTEXT_DECL"); + request.clearHeader("Shib-Attributes", "HTTP_SHIB_ATTRIBUTES"); + request.clearHeader("Shib-Assertion-Count", "HTTP_SHIB_ASSERTION_COUNT"); //request.clearHeader("Shib-Application-ID"); handle inside app method request.getApplication().clearAttributeHeaders(request); } @@ -411,7 +411,7 @@ pair ServiceProvider::doExport(SPRequest& request, bool requireSessio catch (exception& e) { TemplateParameters tp(&e); tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?')); - return make_pair(true,sendError(request, app, "rm", tp)); + return make_pair(true,sendError(request, app, "session", tp)); } #ifndef _DEBUG catch (...) { @@ -419,7 +419,7 @@ pair ServiceProvider::doExport(SPRequest& request, bool requireSessio tp.m_map["errorType"] = "Unexpected Error"; tp.m_map["errorText"] = "Caught an unknown exception."; tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?')); - return make_pair(true,sendError(request, app, "rm", tp)); + return make_pair(true,sendError(request, app, "session", tp)); } #endif } diff --git a/shibsp/impl/XMLServiceProvider.cpp b/shibsp/impl/XMLServiceProvider.cpp index 9d94401..ed4d851 100644 --- a/shibsp/impl/XMLServiceProvider.cpp +++ b/shibsp/impl/XMLServiceProvider.cpp @@ -146,8 +146,8 @@ namespace { DDF header; DDF ret=DDF(NULL).list(); DDFJanitor jret(ret); - for (vector::const_iterator i = m_unsetHeaders.begin(); i!=m_unsetHeaders.end(); ++i) { - header = DDF(NULL).string(i->c_str()); + for (vector< pair >::const_iterator i = m_unsetHeaders.begin(); i!=m_unsetHeaders.end(); ++i) { + header = DDF(i->first.c_str()).string(i->second.c_str()); ret.add(header); } out << ret; @@ -179,7 +179,7 @@ namespace { #endif #endif set m_remoteUsers; - mutable vector m_unsetHeaders; + mutable vector< pair > m_unsetHeaders; RWLock* m_unsetLock; // manage handler objects @@ -491,11 +491,18 @@ XMLApplication::XMLApplication( pos = strchr(start,' '); if (pos) *pos=0; - m_unsetHeaders.push_back(start); + + string transformed("HTTP_"); + const char* pch = start; + while (*pch) { + transformed += (isalnum(*pch) ? toupper(*pch) : '_'); + pch++; + } + m_unsetHeaders.push_back(pair(start,transformed)); start = pos ? pos+1 : NULL; } free(dup); - m_unsetHeaders.push_back("Shib-Application-ID"); + m_unsetHeaders.push_back(pair("Shib-Application-ID","HTTP_SHIB_APPLICATION_ID")); } } @@ -722,18 +729,33 @@ XMLApplication::XMLApplication( } if (m_unsetHeaders.empty()) { + vector unsetHeaders; if (m_attrExtractor) { Locker extlock(m_attrExtractor); - m_attrExtractor->getAttributeIds(m_unsetHeaders); + m_attrExtractor->getAttributeIds(unsetHeaders); } if (m_attrResolver) { Locker reslock(m_attrResolver); - m_attrResolver->getAttributeIds(m_unsetHeaders); + m_attrResolver->getAttributeIds(unsetHeaders); + } + if (unsetHeaders.empty()) { + if (m_base) + m_unsetHeaders.insert(m_unsetHeaders.end(), m_base->m_unsetHeaders.begin(), m_base->m_unsetHeaders.end()); + else + m_unsetHeaders.push_back(pair("Shib-Application-ID","HTTP_SHIB_APPLICATION_ID")); + } + else { + for (vector::const_iterator hdr = unsetHeaders.begin(); hdr!=unsetHeaders.end(); ++hdr) { + string transformed("HTTP_"); + const char* pch = hdr->c_str(); + while (*pch) { + transformed += (isalnum(*pch) ? toupper(*pch) : '_'); + pch++; + } + m_unsetHeaders.push_back(pair(*hdr,transformed)); + } + m_unsetHeaders.push_back(pair("Shib-Application-ID","HTTP_SHIB_APPLICATION_ID")); } - if (m_base && m_unsetHeaders.empty()) - m_unsetHeaders.insert(m_unsetHeaders.end(), m_base->m_unsetHeaders.begin(), m_base->m_unsetHeaders.end()); - else - m_unsetHeaders.push_back("Shib-Application-ID"); } } @@ -932,8 +954,8 @@ const Handler* XMLApplication::getHandler(const char* path) const void XMLApplication::clearAttributeHeaders(SPRequest& request) const { if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) { - for (vector::const_iterator i = m_unsetHeaders.begin(); i!=m_unsetHeaders.end(); ++i) - request.clearHeader(i->c_str()); + for (vector< pair >::const_iterator i = m_unsetHeaders.begin(); i!=m_unsetHeaders.end(); ++i) + request.clearHeader(i->first.c_str(), i->second.c_str()); return; } @@ -951,7 +973,7 @@ void XMLApplication::clearAttributeHeaders(SPRequest& request) const if (out.islist()) { DDF header = out.first(); while (header.isstring()) { - m_unsetHeaders.push_back(header.string()); + m_unsetHeaders.push_back(pair(header.name(),header.string())); header = out.next(); } } @@ -964,8 +986,8 @@ void XMLApplication::clearAttributeHeaders(SPRequest& request) const // Now holding read lock. SharedLock unsetLock(m_unsetLock, false); - for (vector::const_iterator i = m_unsetHeaders.begin(); i!=m_unsetHeaders.end(); ++i) - request.clearHeader(i->c_str()); + for (vector< pair >::const_iterator i = m_unsetHeaders.begin(); i!=m_unsetHeaders.end(); ++i) + request.clearHeader(i->first.c_str(), i->second.c_str()); } short XMLConfigImpl::acceptNode(const DOMNode* node) const -- 2.1.4