/*
- * Copyright 2001-2005 Internet2
- *
+ * Copyright 2001-2009 Internet2
+ *
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
namespace {
ShibTargetConfig* g_Config=NULL;
string g_ServerName;
- string g_ServerScheme;
string g_unsetHeaderValue;
+ set<string> g_allowedSchemes;
bool g_checkSpoofing = false;
bool g_catchAll = true;
}
}
}
}
- name=pblock_findval("server-scheme",pb);
- if (name)
- g_ServerScheme=name;
log_error(LOG_INFORM,"nsapi_shib_init",sn,rq,"nsapi_shib loaded for host (%s)",g_ServerName.c_str());
Locker locker(conf);
const IPropertySet* props=conf->getPropertySet("Local");
if (props) {
- pair<bool,const char*> unsetValue=props->getString("unsetHeaderValue");
- if (unsetValue.first)
- g_unsetHeaderValue = unsetValue.second;
+ pair<bool,const char*> str=props->getString("unsetHeaderValue");
+ if (str.first)
+ g_unsetHeaderValue = str.second;
+
+ str=props->getString("allowedSchemes");
+ if (str.first) {
+ string schemes=str.second;
+ unsigned int j=0;
+ for (unsigned int i=0; i < schemes.length(); i++) {
+ if (schemes.at(i)==' ') {
+ g_allowedSchemes.insert(schemes.substr(j, i-j));
+ j = i+1;
+ }
+ }
+ g_allowedSchemes.insert(schemes.substr(j, schemes.length()-j));
+ }
+
pair<bool,bool> flag=props->getBool("checkSpoofing");
g_checkSpoofing = !flag.first || flag.second;
flag=props->getBool("catchAll");
g_catchAll = !flag.first || flag.second;
}
+ if (g_allowedSchemes.empty()) {
+ g_allowedSchemes.insert("https");
+ g_allowedSchemes.insert("http");
+ }
}
catch (exception&) {
g_Config=NULL;
class ShibTargetNSAPI : public ShibTarget
{
+ void checkString(const string& s, const char* msg) {
+ string::const_iterator e = s.end();
+ for (string::const_iterator i=s.begin(); i!=e; ++i) {
+ if (iscntrl(*i))
+ throw FatalProfileException(msg);
+ }
+ }
+
public:
ShibTargetNSAPI(pblock* pb, Session* sn, Request* rq) : m_pb(pb), m_sn(sn), m_rq(rq), m_firsttime(true) {
- // Get everything but hostname...
+
+ // To determine whether SSL is active or not, we're supposed to rely
+ // on the security_active macro. For iPlanet 4.x, this works.
+ // For Sun 7.x, it's useless and appears to be on or off based
+ // on whether ANY SSL support is enabled for a vhost. Sun 6.x is unknown.
+ // As a fix, there's a conf variable called $security that can be mapped
+ // into a function parameter: security_active="$security"
+ // We check for this parameter, and rely on the macro if it isn't set.
+ // This doubles as a scheme virtualizer for load balanced scenarios
+ // since you can set the parameter to 1 or 0 as needed.
+ const char* scheme;
+ const char* sa = pblock_findval("security_active", pb);
+ if (sa)
+ scheme = (*sa == '1') ? "https" : "http";
+ else if (security_active)
+ scheme = "https";
+ else
+ scheme = "http";
+
+ // A similar issue exists for the port. server_portnum is no longer
+ // working on at least Sun 7.x, and returns the first listener's port
+ // rather than whatever port is actually used for the request. Nice job, Sun.
+ sa = pblock_findval("server_portnum", pb);
+ int port = (sa && *sa) ? atoi(sa) : server_portnum;
+
+ // Get everything else but hostname...
const char* uri=pblock_findval("uri", rq->reqpb);
const char* qstr=pblock_findval("query", rq->reqpb);
- int port=server_portnum;
- const char* scheme=security_active ? "https" : "http";
const char* host=NULL;
string url;
url=uri;
if (qstr)
url=url + '?' + qstr;
-
+
#ifdef vs_is_default_vs
// This is 6.0 or later, so we can distinguish requests to name-based vhosts.
if (!vs_is_default_vs(request_get_vs(m_rq)))
char* content_type = "";
request_header("content-type", &content_type, sn, rq);
-
+
const char* remote_ip = pblock_findval("ip", sn->client);
const char* method = pblock_findval("method", rq->reqpb);
init(scheme, host, port, url.c_str(), content_type, remote_ip, method);
-
+
// See if this is the first time we've run.
method = pblock_findval("auth-type", rq->vars);
if (method && !strcmp(method, "shibboleth"))
m_firsttime = false;
- if (!m_firsttime)
+ if (!m_firsttime || rq->orig_rq)
log(LogLevelDebug, "nsapi_shib function running more than once");
}
~ShibTargetNSAPI() {
string cookie = name + '=' + value;
pblock_nvinsert("Set-Cookie", cookie.c_str(), m_rq->srvhdrs);
}
- virtual string getArgs(void) {
+ virtual string getArgs(void) {
const char *q = pblock_findval("query", m_rq->reqpb);
return string(q ? q : "");
}
string cgistr;
while (cl && ch != IO_EOF) {
ch=netbuf_getc(m_sn->inbuf);
-
+
// Check for error.
if(ch==IO_ERROR)
break;
}
}
virtual void clearHeader(const string &name) {
- if (m_firsttime && g_checkSpoofing && m_allhttp.empty()) {
+ if (g_checkSpoofing && m_firsttime && !m_rq->orig_rq && m_allhttp.empty()) {
// Populate the set of client-supplied headers for spoof checking.
const pb_entry* entry;
for (int i=0; i<m_rq->headers->hsize; ++i) {
}
}
if (name=="REMOTE_USER") {
- if (m_firsttime && g_checkSpoofing && m_allhttp.count("HTTP_REMOTE_USER") > 0)
+ if (g_checkSpoofing && m_firsttime && !m_rq->orig_rq && m_allhttp.count("HTTP_REMOTE_USER") > 0)
throw SAMLException("Attempt to spoof header ($1) was detected.", params(1, name.c_str()));
param_free(pblock_remove("auth-user",m_rq->vars));
param_free(pblock_remove("remote-user",m_rq->headers));
+ pblock_nvinsert("remote-user", g_unsetHeaderValue.c_str(), m_rq->headers);
}
else {
- if (m_firsttime && g_checkSpoofing) {
+ if (g_checkSpoofing && m_firsttime && !m_rq->orig_rq) {
// Map to the expected CGI variable name.
string transformed("HTTP_");
const char* pch = name.c_str();
return string(hdr ? hdr : "");
}
virtual void setRemoteUser(const string &user) {
+ param_free(pblock_remove("remote-user",m_rq->headers));
pblock_nvinsert("remote-user", user.c_str(), m_rq->headers);
pblock_nvinsert("auth-user", user.c_str(), m_rq->vars);
}
const string& content_type="text/html",
const saml::Iterator<header_t>& headers=EMPTY(header_t)
) {
+ checkString(content_type, "Detected control character in a response header.");
param_free(pblock_remove("content-type", m_rq->srvhdrs));
pblock_nvinsert("content-type", content_type.c_str(), m_rq->srvhdrs);
pblock_nninsert("content-length", msg.length(), m_rq->srvhdrs);
pblock_nvinsert("connection","close",m_rq->srvhdrs);
while (headers.hasNext()) {
const header_t& h=headers.next();
+ checkString(h.first, "Detected control character in a response header.");
+ checkString(h.second, "Detected control character in a response header.");
pblock_nvinsert(h.first.c_str(), h.second.c_str(), m_rq->srvhdrs);
}
protocol_status(m_sn, m_rq, code, NULL);
return (void*)REQ_EXIT;
}
virtual void* sendRedirect(const string& url) {
+ checkString(url, "Detected control character in an attempted redirect.");
+ if (g_allowedSchemes.find(url.substr(0, url.find(':'))) == g_allowedSchemes.end())
+ throw FatalProfileException("Invalid scheme in attempted redirect.");
param_free(pblock_remove("content-type", m_rq->srvhdrs));
pblock_nninsert("content-length", 0, m_rq->srvhdrs);
pblock_nvinsert("expires", "01-Jan-1997 12:00:00 GMT", m_rq->srvhdrs);
ostringstream threadid;
threadid << "[" << getpid() << "] nsapi_shib" << '\0';
saml::NDC ndc(threadid.str().c_str());
-
+
try {
ShibTargetNSAPI stn(pb, sn, rq);
-
+
// Check user authentication
pair<bool,void*> res = stn.doCheckAuthN();
if (res.first) return (int)res.second;
-
+
// user authN was okay -- export the assertions now
param_free(pblock_remove("auth-user",rq->vars));
// This seems to be required in order to eventually set
pblock_nvinsert("auth-type","shibboleth",rq->vars);
res = stn.doExportAssertions();
if (res.first) return (int)res.second;
-
+
// Check the Authorization
res = stn.doCheckAuthZ();
if (res.first) return (int)res.second;
-
+
// this user is ok.
return REQ_PROCEED;
}
ostringstream threadid;
threadid << "[" << getpid() << "] shib_handler" << '\0';
saml::NDC ndc(threadid.str().c_str());
-
+
try {
ShibTargetNSAPI stn(pb, sn, rq);
-
+
pair<bool,void*> res = stn.doHandler();
if (res.first) return (int)res.second;
-
+
return WriteClientError(sn, rq, FUNC, "Shibboleth handler did not do anything.");
}
catch (exception& e) {
void lock() { m_mapper->lock(); }
void unlock() { m_stKey->setData(NULL); m_propsKey->setData(NULL); m_mapper->unlock(); }
Settings getSettings(ShibTarget* st) const;
-
+
pair<bool,bool> getBool(const char* name, const char* ns=NULL) const;
pair<bool,const char*> getString(const char* name, const char* ns=NULL) const;
pair<bool,const XMLCh*> getXMLString(const char* name, const char* ns=NULL) const;