* limitations under the License.
*/
-/*
- * mod_apache.cpp -- the core Apache Module code
- *
- * Created by: Derek Atkins <derek@ihtfp.com>
- *
- * $Id$
+/**
+ * mod_apache.cpp
+ *
+ * Apache module implementation
*/
#define SHIBSP_LITE
#define CORE_PRIVATE
#include <http_core.h>
#include <http_log.h>
+#include <http_request.h>
#ifndef SHIB_APACHE_13
-#include <http_request.h>
#include <apr_buckets.h>
#include <apr_strings.h>
#include <apr_pools.h>
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);
mutable string m_body;
mutable bool m_gotBody;
mutable vector<string> m_certs;
+ set<string> m_allhttp;
public:
request_rec* m_req;
#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) {
pair<bool,const char*> unsetValue=props->getString("unsetHeaderValue");
if (unsetValue.first)
g_unsetHeaderValue = unsetValue.second;
+ pair<bool,bool> checkSpoofing=props->getBool("checkSpoofing");
+ if (checkSpoofing.first && !checkSpoofing.second)
+ g_checkSpoofing = false;
}
// Set the cleanup handler
(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"),
};
#else
-#error "undefined APACHE version"
+#error "unsupported Apache version"
#endif
}
console.logger \
syslog.logger \
accessError.html \
- rmError.html \
sessionError.html \
metadataError.html \
bindingTemplate.html \
console.logger \
syslog.logger \
accessError.html \
- rmError.html \
sessionError.html \
metadataError.html \
sslError.html \
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" type="text/css" href="<shibmlp styleSheet/>" />
- <title>Session Creation Failure</title>
+ <title><shibmlp errorType/></title>
</head>
<body>
<div class="head">
<img src="<shibmlp logoLocation/>" alt="Logo" />
-<h1>Session Creation Failure</h1>
+<h1><shibmlp errorType/></h1>
</div>
-<p>The inter-institutional access system was unable to successfully build a
-login session for you at <shibmlp now /></p>
+<p>The inter-institutional access system encountered an error at <shibmlp now /></p>
<p>To report this problem, please contact the site administrator at
<a href="mailto:<shibmlp supportContact/>"><shibmlp supportContact/></a>.
</p>
<p>Please include the following message in any email:</p>
-<p class="error">Session creation failure at (<shibmlp requestURL/>)</p>
-<p><shibmlp errorType/></p>
+<p class="error"><shibmlp errorType/> at (<shibmlp requestURL/>)</p>
+
+<p><shibmlp errorText/></p>
</body>
</html>
-->
<Errors session="@-PKGSYSCONFDIR-@/sessionError.html"
metadata="@-PKGSYSCONFDIR-@/metadataError.html"
- rm="@-PKGSYSCONFDIR-@/rmError.html"
access="@-PKGSYSCONFDIR-@/accessError.html"
ssl="@-PKGSYSCONFDIR-@/sslError.html"
supportContact="root@localhost"
\r
<annotation>\r
<documentation>\r
- 2.0 schema for XML-based configuration of Shibboleth Native SP instances.\r
- First appearing in Shibboleth 2.0 release.\r
- </documentation>\r
- </annotation>\r
+ 2.0 schema for XML-based configuration of Shibboleth Native SP instances.\r
+ First appearing in Shibboleth 2.0 release.\r
+ </documentation>\r
+ </annotation>\r
\r
- <simpleType name="string">
- <restriction base="string">
+ <simpleType name="string">\r
+ <restriction base="string">\r
<minLength value="1"/>\r
- </restriction>
+ </restriction>\r
</simpleType>\r
\r
<simpleType name="listOfStrings">\r
</complexType>\r
\r
<element name="SPConfig">\r
- <complexType>
- <annotation>
- <documentation>Root of configuration</documentation>
- </annotation>
- <sequence>
- <element ref="conf:Extensions" minOccurs="0"/>
- <element ref="conf:OutOfProcess"/>
- <element ref="conf:InProcess"/>
- <element ref="conf:Applications"/>
- <element ref="conf:SecurityPolicies"/>
- </sequence>
- <attribute name="logger" type="anyURI"/>
- <attribute name="clockSkew" type="unsignedInt"/>
- <anyAttribute namespace="##other" processContents="lax"/>
+ <complexType>\r
+ <annotation>\r
+ <documentation>Root of configuration</documentation>\r
+ </annotation>\r
+ <sequence>\r
+ <element ref="conf:Extensions" minOccurs="0"/>\r
+ <element ref="conf:OutOfProcess"/>\r
+ <element ref="conf:InProcess"/>\r
+ <element ref="conf:Applications"/>\r
+ <element ref="conf:SecurityPolicies"/>\r
+ </sequence>\r
+ <attribute name="logger" type="anyURI"/>\r
+ <attribute name="clockSkew" type="unsignedInt"/>\r
+ <anyAttribute namespace="##other" processContents="lax"/>\r
</complexType>\r
</element>\r
\r
</complexType>\r
</element>\r
\r
- <element name="ReplayCache">
+ <element name="ReplayCache">\r
<annotation>\r
<documentation>Ties ReplayCache to a custom StorageService</documentation>\r
</annotation>\r
<complexType>\r
- <sequence/>
+ <sequence/>\r
<attribute name="StorageService" type="IDREF" use="required"/>\r
</complexType>\r
- </element>
+ </element>\r
\r
- <element name="ArtifactMap">
+ <element name="ArtifactMap">\r
<annotation>\r
<documentation>Customizes an ArtifactMap</documentation>\r
</annotation>\r
<complexType>\r
- <sequence/>
- <attribute name="StorageService" type="IDREF"/>
- <attribute name="context" type="conf:string"/>
+ <sequence/>\r
+ <attribute name="StorageService" type="IDREF"/>\r
+ <attribute name="context" type="conf:string"/>\r
<attribute name="artifactTTL" type="unsignedInt" default="180"/>\r
- </complexType>
+ </complexType>\r
</element>\r
\r
<element name="OutOfProcess">\r
<documentation>Container for shibd out-of-process configuration</documentation>\r
</annotation>\r
<complexType>\r
- <sequence>
- <element ref="conf:Extensions" minOccurs="0"/>
- <choice>
- <element name="UnixListener">
- <complexType>
- <attribute name="address" type="conf:string" use="required"/>
- </complexType>
- </element>
- <element name="TCPListener">
- <complexType>
- <attribute name="address" type="conf:string" use="required"/>
- <attribute name="port" type="unsignedInt" use="required"/>
- <attribute name="acl" type="conf:listOfStrings" default="127.0.0.1"/>
- </complexType>
- </element>
- <element name="Listener" type="conf:PluggableType"/>
- </choice>
- <element ref="conf:StorageService" minOccurs="0" maxOccurs="unbounded"/>
- <element ref="conf:SessionCache" minOccurs="0"/>
+ <sequence>\r
+ <element ref="conf:Extensions" minOccurs="0"/>\r
+ <choice>\r
+ <element name="UnixListener">\r
+ <complexType>\r
+ <attribute name="address" type="conf:string" use="required"/>\r
+ </complexType>\r
+ </element>\r
+ <element name="TCPListener">\r
+ <complexType>\r
+ <attribute name="address" type="conf:string" use="required"/>\r
+ <attribute name="port" type="unsignedInt" use="required"/>\r
+ <attribute name="acl" type="conf:listOfStrings" default="127.0.0.1"/>\r
+ </complexType>\r
+ </element>\r
+ <element name="Listener" type="conf:PluggableType"/>\r
+ </choice>\r
+ <element ref="conf:StorageService" minOccurs="0" maxOccurs="unbounded"/>\r
+ <element ref="conf:SessionCache" minOccurs="0"/>\r
<element ref="conf:ReplayCache" minOccurs="0"/>\r
- <element ref="conf:ArtifactMap" minOccurs="0"/>
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
- </sequence>
- <attribute name="logger" type="anyURI"/>
+ <element ref="conf:ArtifactMap" minOccurs="0"/>\r
+ <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>\r
+ </sequence>\r
+ <attribute name="logger" type="anyURI"/>\r
<anyAttribute namespace="##other" processContents="lax"/>\r
</complexType>\r
</element>\r
</documentation>\r
</annotation>\r
<complexType>\r
- <sequence>
- <element ref="conf:Extensions" minOccurs="0"/>
+ <sequence>\r
+ <element ref="conf:Extensions" minOccurs="0"/>\r
<element ref="conf:SessionCache" minOccurs="0"/>\r
- <element name="RequestMapper" type="conf:PluggableType"/>
- <element name="Implementation" minOccurs="0">
- <complexType>
- <sequence>
- <element ref="conf:ISAPI" minOccurs="0"/>
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
- </sequence>
- </complexType>
- </element>
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
- </sequence>
- <attribute name="logger" type="anyURI"/>
- <attribute name="unsetHeaderValue" type="string" use="optional"/>\r
+ <element name="RequestMapper" type="conf:PluggableType"/>\r
+ <element name="Implementation" minOccurs="0">\r
+ <complexType>\r
+ <sequence>\r
+ <element ref="conf:ISAPI" minOccurs="0"/>\r
+ <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>\r
+ </sequence>\r
+ </complexType>\r
+ </element>\r
+ <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>\r
+ </sequence>\r
+ <attribute name="logger" type="anyURI"/>\r
+ <attribute name="unsetHeaderValue" type="string"/>\r
+ <attribute name="checkSpoofing" type="boolean"/>\r
<anyAttribute namespace="##other" processContents="lax"/>\r
</complexType>\r
</element>\r
<element ref="conf:Sessions"/>\r
<element ref="conf:Errors"/>\r
<element ref="conf:DefaultRelyingParty"/>\r
- <element ref="saml:Audience" minOccurs="0" maxOccurs="unbounded"/>
- <element name="MetadataProvider" type="conf:PluggableType"/>
+ <element ref="saml:Audience" minOccurs="0" maxOccurs="unbounded"/>\r
+ <element name="MetadataProvider" type="conf:PluggableType"/>\r
<element name="TrustEngine" type="conf:PluggableType"/>\r
<element name="AttributeExtractor" type="conf:PluggableType" minOccurs="0"/>\r
<element name="AttributeResolver" type="conf:PluggableType" minOccurs="0"/>\r
<element ref="md:ArtifactResolutionService"/>\r
<element ref="md:SingleLogoutService"/>\r
<element ref="md:ManageNameIDService"/>\r
- <element name="Handler">
+ <element name="Handler">\r
<complexType>\r
<complexContent>\r
<restriction base="conf:PluggableType">\r
</complexType>\r
</element>\r
\r
- <attribute name="policyId" type="conf:string">
- <annotation>
- <documentation>Used to reference Policy elements from profile endpoints.</documentation>
- </annotation>
+ <attribute name="policyId" type="conf:string">\r
+ <annotation>\r
+ <documentation>Used to reference Policy elements from profile endpoints.</documentation>\r
+ </annotation>\r
</attribute>\r
\r
<element name="SessionInitiator">\r
<attribute name="authType" type="conf:string"/>\r
<attribute name="authUsername" type="conf:string"/>\r
<attribute name="authPassword" type="conf:string"/>\r
- <attribute name="signRequests" type="boolean"/>
+ <attribute name="signRequests" type="boolean"/>\r
<attribute name="signResponses" type="boolean"/>\r
<attribute name="signatureAlg" type="anyURI"/>\r
<attribute name="digestAlg" type="anyURI"/>\r
<attribute name="artifactEndpointIndex" type="unsignedShort"/>\r
</attributeGroup>\r
\r
- <element name="SecurityPolicies">
+ <element name="SecurityPolicies">\r
<annotation>\r
<documentation>Container for specifying sets of policy rules to apply to incoming messages</documentation>\r
</annotation>\r
<documentation>Specifies a set of SecurityPolicyRule plugins</documentation>\r
</annotation>\r
<complexType>\r
- <sequence>
- <element name="Rule" type="conf:PluggableType" minOccurs="1" maxOccurs="unbounded"/>
- </sequence>
+ <sequence>\r
+ <element name="Rule" type="conf:PluggableType" minOccurs="1" maxOccurs="unbounded"/>\r
+ </sequence>\r
<attribute name="id" type="conf:string" use="required"/>\r
<attribute name="validate" type="boolean" default="false"/>\r
<attribute name="signedAssertions" type="boolean" default="false"/>\r
/**
* 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.
}
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);
}
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 (...) {
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
}
DDF header;
DDF ret=DDF(NULL).list();
DDFJanitor jret(ret);
- for (vector<string>::const_iterator i = m_unsetHeaders.begin(); i!=m_unsetHeaders.end(); ++i) {
- header = DDF(NULL).string(i->c_str());
+ for (vector< pair<string,string> >::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;
#endif
#endif
set<string> m_remoteUsers;
- mutable vector<string> m_unsetHeaders;
+ mutable vector< pair<string,string> > m_unsetHeaders;
RWLock* m_unsetLock;
// manage handler objects
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<string,string>(start,transformed));
start = pos ? pos+1 : NULL;
}
free(dup);
- m_unsetHeaders.push_back("Shib-Application-ID");
+ m_unsetHeaders.push_back(pair<string,string>("Shib-Application-ID","HTTP_SHIB_APPLICATION_ID"));
}
}
}
if (m_unsetHeaders.empty()) {
+ vector<string> 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<string,string>("Shib-Application-ID","HTTP_SHIB_APPLICATION_ID"));
+ }
+ else {
+ for (vector<string>::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<string,string>(*hdr,transformed));
+ }
+ m_unsetHeaders.push_back(pair<string,string>("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");
}
}
void XMLApplication::clearAttributeHeaders(SPRequest& request) const
{
if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) {
- for (vector<string>::const_iterator i = m_unsetHeaders.begin(); i!=m_unsetHeaders.end(); ++i)
- request.clearHeader(i->c_str());
+ for (vector< pair<string,string> >::const_iterator i = m_unsetHeaders.begin(); i!=m_unsetHeaders.end(); ++i)
+ request.clearHeader(i->first.c_str(), i->second.c_str());
return;
}
if (out.islist()) {
DDF header = out.first();
while (header.isstring()) {
- m_unsetHeaders.push_back(header.string());
+ m_unsetHeaders.push_back(pair<string,string>(header.name(),header.string()));
header = out.next();
}
}
// Now holding read lock.
SharedLock unsetLock(m_unsetLock, false);
- for (vector<string>::const_iterator i = m_unsetHeaders.begin(); i!=m_unsetHeaders.end(); ++i)
- request.clearHeader(i->c_str());
+ for (vector< pair<string,string> >::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