<data>
<item id="org.eclipse.cdt.core.pathentry">
-<pathentry kind="src" path="shibsp"/>
+<pathentry kind="src" path="apache"/>
<pathentry kind="out" path=""/>
<pathentry kind="src" path="odbc-store"/>
-<pathentry kind="src" path="apache"/>
+<pathentry excluding="util/|impl/|security/|metadata/|remoting/|remoting/impl/" kind="src" path="shibsp"/>
+<pathentry kind="src" path="shibsp/impl"/>
+<pathentry kind="src" path="shibsp/metadata"/>
+<pathentry excluding="impl/" kind="src" path="shibsp/remoting"/>
+<pathentry kind="src" path="shibsp/remoting/impl"/>
+<pathentry kind="src" path="shibsp/security"/>
+<pathentry kind="src" path="shibsp/util"/>
</item>
</data>
</cdtproject>
# define _CRT_SECURE_NO_DEPRECATE 1
#endif
+#include <shibsp/AccessControl.h>
#include <shibsp/exceptions.h>
+#include <shibsp/RequestMapper.h>
#include <shibsp/SPConfig.h>
// SAML Runtime
#include <shib/shib.h>
#include <shib-target/shib-target.h>
#include <xercesc/util/regx/RegularExpression.hpp>
+#include <xmltooling/util/NDC.h>
#include <xmltooling/util/Threads.h>
#ifdef WIN32
shib_request_config* rc=(shib_request_config*)ap_pcalloc(r->pool,sizeof(shib_request_config));
ap_set_module_config (r->request_config, &mod_shib, rc);
memset(rc, 0, sizeof(shib_request_config));
- ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r), "shib_init_rc\n");
+ ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r), "shib_init_rc");
return rc;
}
{
mutable string m_body;
mutable bool m_gotBody;
+ vector<XSECCryptoX509*> m_certs;
public:
request_rec* m_req;
m_sc = (shib_server_config*)ap_get_module_config(req->server->module_config, &mod_shib);
m_dc = (shib_dir_config*)ap_get_module_config(req->per_dir_config, &mod_shib);
m_rc = (shib_request_config*)ap_get_module_config(req->request_config, &mod_shib);
+ m_req = req;
init(
m_sc->szScheme ? m_sc->szScheme : ap_http_method(req),
req->connection->remote_ip,
req->method
);
-
- m_req = req;
}
virtual ~ShibTargetApache() {}
- virtual void log(ShibLogLevel level, const string &msg) {
- ShibTarget::log(level,msg);
-#ifdef SHIB_APACHE_13
- ap_log_rerror(APLOG_MARK,
- (level == LogLevelDebug ? APLOG_DEBUG :
- (level == LogLevelInfo ? APLOG_INFO :
- (level == LogLevelWarn ? APLOG_WARNING : APLOG_ERR)))|APLOG_NOERRNO, SH_AP_R(m_req), msg.c_str());
-#else
- if (level == LogLevelError)
- ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, SH_AP_R(m_req), msg.c_str());
-#endif
+ const char* getScheme() const {
+ return m_sc->szScheme ? m_sc->szScheme : ap_http_method(m_req);
}
- virtual string getCookies(void) const {
- const char *c = ap_table_get(m_req->headers_in, "Cookie");
- return string(c ? c : "");
+ const char* getHostname() const {
+ return ap_get_server_name(m_req);
}
- virtual void setCookie(const string &name, const string &value) {
- char* val = ap_psprintf(m_req->pool, "%s=%s", name.c_str(), value.c_str());
-#ifdef SHIB_DEFERRED_HEADERS
- ap_table_addn(m_rc->hdr_err, "Set-Cookie", val);
-#else
- ap_table_addn(m_req->err_headers_out, "Set-Cookie", val);
-#endif
+ int getPort() const {
+ return ap_get_server_port(m_req);
+ }
+ const char* getRequestURI() const {
+ return m_req->unparsed_uri;
+ }
+ const char* getMethod() const {
+ return m_req->method;
+ }
+ string getContentType() const {
+ const char* type = ap_table_get(m_req->headers_in, "Content-Type");
+ return type ? type : "";
+ }
+ long getContentLength() const {
+ return m_gotBody ? m_body.length() : m_req->remaining;
+ }
+ string getRemoteAddr() const {
+ return m_req->connection->remote_ip;
+ }
+ void log(SPLogLevel level, const string& msg) const {
+ AbstractSPRequest::log(level,msg);
+ ap_log_rerror(
+ APLOG_MARK,
+ (level == SPDebug ? APLOG_DEBUG :
+ (level == SPInfo ? APLOG_INFO :
+ (level == SPWarn ? APLOG_WARNING :
+ (level == SPError ? APLOG_ERR : APLOG_CRIT))))|APLOG_NOERRNO,
+ SH_AP_R(m_req),
+ msg.c_str()
+ );
}
- virtual const char* getQueryString() const { return m_req->args; }
- virtual const char* getRequestBody() const {
+ const char* getQueryString() const { return m_req->args; }
+ const char* getRequestBody() const {
if (m_gotBody)
return m_body.c_str();
// Read the posted data
if (ap_setup_client_block(m_req, REQUEST_CHUNKED_ERROR))
- throw saml::SAMLException("Apache function (setup_client_block) failed while reading POST request body.");
+ throw opensaml::BindingException("Apache function (setup_client_block) failed while reading POST request body.");
if (!ap_should_client_block(m_req))
- throw saml::SAMLException("Apache function (should_client_block) failed while reading POST request body.");
+ throw opensaml::BindingException("Apache function (should_client_block) failed while reading POST request body.");
if (m_req->remaining > 1024*1024)
- throw saml::SAMLException("Blocked POST request body larger than size limit.");
+ throw opensaml::BindingException("Blocked POST request body larger than size limit.");
m_gotBody=true;
char buff[HUGE_STRING_LEN];
ap_hard_timeout("[mod_shib] getRequestBody", m_req);
ap_kill_timeout(m_req);
return m_body.c_str();
}
- virtual void clearHeader(const string &name) {
+ void clearHeader(const char* name) {
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.c_str());
+ if (m_rc && m_rc->env) ap_table_unset(m_rc->env, name);
} 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.c_str());
- ap_table_set(m_req->headers_in, name.c_str(), g_unsetHeaderValue.c_str());
+ ap_table_unset(m_req->headers_in, name);
+ ap_table_set(m_req->headers_in, name, g_unsetHeaderValue.c_str());
}
}
- virtual void setHeader(const string &name, const string &value) {
+ void setHeader(const char* name, const char* value) {
if (m_dc->bUseEnvVars!=0) {
if (!m_rc) {
// this happens on subrequests
m_rc = init_request_config(m_req);
}
if (!m_rc->env) m_rc->env = ap_make_table(m_req->pool, 10);
- // ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(m_req), "shib_set_env: %s=%s\n", name.c_str(), value.c_str()?value.c_str():"Null");
- ap_table_set(m_rc->env, name.c_str(), value.c_str()?value.c_str():"");
- } else {
- // ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(m_req), "shib_set_hdr: %s=%s\n", name.c_str(), value.c_str()?value.c_str():"Null");
- ap_table_set(m_req->headers_in, name.c_str(), value.c_str());
+ // ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(m_req), "shib_set_env: %s=%s\n", name, value?value:"Null");
+ ap_table_set(m_rc->env, name, value?value:"");
+ }
+ else {
+ ap_table_set(m_req->headers_in, name, value);
}
}
- virtual string getHeader(const string &name) {
- const char *hdr;
+ string getHeader(const char* name) const {
+ const char* hdr = ap_table_get(m_req->headers_in, name);
+ return string(hdr ? hdr : "");
+ }
+ string getSecureHeader(const char* name) const {
if (m_dc->bUseEnvVars!=0) {
- if (m_rc && m_rc->env) hdr = ap_table_get(m_rc->env, name.c_str());
- else hdr = NULL;
- // ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(m_req), "shib_get_hdr_env: %s=%s\n", name.c_str(), hdr?hdr:"NULL");
- } else {
- hdr = ap_table_get(m_req->headers_in, name.c_str());
- // ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(m_req), "shib_get_hdr: %s=%s\n", name.c_str(), hdr?hdr:"NULL");
+ const char *hdr;
+ if (m_rc && m_rc->env)
+ hdr = ap_table_get(m_rc->env, name);
+ else
+ hdr = NULL;
+ return string(hdr ? hdr : "");
}
- return string(hdr ? hdr : "");
+ return getHeader(name);
}
- virtual void setRemoteUser(const string &user) {
- SH_AP_USER(m_req) = ap_pstrdup(m_req->pool, user.c_str());
+ void setRemoteUser(const char* user) {
+ SH_AP_USER(m_req) = user ? ap_pstrdup(m_req->pool, user) : NULL;
}
- virtual string getRemoteUser(void) {
+ string getRemoteUser() const {
return string(SH_AP_USER(m_req) ? SH_AP_USER(m_req) : "");
}
- virtual void* sendPage(
- const string& msg,
- int code=200,
- const string& content_type="text/html",
- const saml::Iterator<header_t>& headers=EMPTY(header_t)
- ) {
- m_req->content_type = ap_psprintf(m_req->pool, content_type.c_str());
- while (headers.hasNext()) {
- const header_t& h=headers.next();
- ap_table_set(m_req->headers_out, h.first.c_str(), h.second.c_str());
- }
+ void setContentType(const char* type) {
+ m_req->content_type = ap_psprintf(m_req->pool, type);
+ }
+ void setResponseHeader(const char* name, const char* value) {
+#ifdef SHIB_DEFERRED_HEADERS
+ if (!m_rc)
+ // this happens on subrequests
+ m_rc = init_request_config(m_req);
+ ap_table_add(m_rc->hdr_err, name, value);
+ ap_table_add(m_rc->hdr_out, name, value);
+#else
+ ap_table_add(m_req->err_headers_out, name, value);
+#endif
+ }
+ long sendResponse(istream& in, long status) {
ap_send_http_header(m_req);
- ap_rprintf(m_req, msg.c_str());
- return (void*)((code==200) ? DONE : code);
+ char buf[1024];
+ while (in) {
+ in.read(buf,1024);
+ ap_rwrite(buf,in.gcount(),m_req);
+ }
+ return ((status==SAML_HTTP_STATUS_OK) ? DONE : status);
+ }
+ long sendRedirect(const char* url) {
+ ap_table_set(m_req->headers_out, "Location", url);
+ return REDIRECT;
}
- virtual void* sendRedirect(const string& url) {
- ap_table_set(m_req->headers_out, "Location", url.c_str());
- return (void*)REDIRECT;
+ const vector<XSECCryptoX509*>& getClientCertificates() const {
+ return m_certs;
}
- virtual void* returnDecline(void) { return (void*)DECLINED; }
- virtual void* returnOK(void) { return (void*)OK; }
+ long returnDecline(void) { return DECLINED; }
+ long returnOK(void) { return OK; }
};
/********************************************************************************/
ostringstream threadid;
threadid << "[" << getpid() << "] shib_check_user" << '\0';
- saml::NDC ndc(threadid.str().c_str());
+ xmltooling::NDC ndc(threadid.str().c_str());
try {
ShibTargetApache sta(r);
// Check user authentication and export information, then set the handler bypass
- pair<bool,void*> res = sta.doCheckAuthN(true);
+ pair<bool,long> res = sta.doCheckAuthN(true);
apr_pool_userdata_setn((const void*)42,g_UserDataKey,NULL,r->pool);
- if (res.first) return (int)(long)res.second;
+ if (res.first) return res.second;
// user auth was okay -- export the assertions now
res = sta.doExportAssertions();
- if (res.first) return (int)(long)res.second;
+ if (res.first) return res.second;
// export happened successfully.. this user is ok.
return OK;
}
- catch (saml::SAMLException& e) {
+ catch (exception& e) {
ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, SH_AP_R(r), "shib_check_user threw an exception: %s", e.what());
return SERVER_ERROR;
}
ostringstream threadid;
threadid << "[" << getpid() << "] shib_handler" << '\0';
- saml::NDC ndc(threadid.str().c_str());
+ xmltooling::NDC ndc(threadid.str().c_str());
#ifndef SHIB_APACHE_13
// With 2.x, this handler always runs, though last.
try {
ShibTargetApache sta(r);
- pair<bool,void*> res = sta.doHandler();
- if (res.first) return (int)(long)res.second;
+ pair<bool,long> res = sta.doHandler();
+ if (res.first) return res.second;
ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, SH_AP_R(r), "doHandler() did not do anything.");
return SERVER_ERROR;
}
- catch (saml::SAMLException& e) {
+ catch (exception& e) {
ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, SH_AP_R(r), "shib_handler threw an exception: %s", e.what());
return SERVER_ERROR;
}
ostringstream threadid;
threadid << "[" << getpid() << "] shib_auth_checker" << '\0';
- saml::NDC ndc(threadid.str().c_str());
+ xmltooling::NDC ndc(threadid.str().c_str());
try {
ShibTargetApache sta(r);
- pair<bool,void*> res = sta.doCheckAuthZ();
- if (res.first) return (int)(long)res.second;
+ pair<bool,long> res = sta.doCheckAuthZ();
+ if (res.first) return res.second;
// We're all okay.
return OK;
}
- catch (saml::SAMLException& e) {
+ catch (exception& e) {
ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, SH_AP_R(r), "shib_auth_checker threw an exception: %s", e.what());
return SERVER_ERROR;
}
}
// Access control plugin that enforces htaccess rules
-class htAccessControl : virtual public IAccessControl
+class htAccessControl : virtual public AccessControl
{
public:
htAccessControl() {}
~htAccessControl() {}
Lockable* lock() {return this;}
void unlock() {}
- bool authorized(
- ShibTarget* st,
- ISessionCacheEntry* entry
- ) const;
+ bool authorized(SPRequest& request, Session* session) const;
};
-saml::IPlugIn* htAccessFactory(const DOMElement* e)
+AccessControl* htAccessFactory(const DOMElement* const & e)
{
return new htAccessControl();
}
-class ApacheRequestMapper : public virtual IRequestMapper, public virtual PropertySet
+class ApacheRequestMapper : public virtual RequestMapper, public virtual PropertySet
{
public:
ApacheRequestMapper(const DOMElement* e);
~ApacheRequestMapper() { delete m_mapper; delete m_htaccess; delete m_staKey; delete m_propsKey; }
Lockable* lock() { return m_mapper->lock(); }
void unlock() { m_staKey->setData(NULL); m_propsKey->setData(NULL); m_mapper->unlock(); }
- Settings getSettings(ShibTarget* st) const;
+ Settings getSettings(const SPRequest& request) 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;
const DOMElement* getElement() const;
private:
- IRequestMapper* m_mapper;
+ RequestMapper* m_mapper;
ThreadKey* m_staKey;
ThreadKey* m_propsKey;
- IAccessControl* m_htaccess;
+ AccessControl* m_htaccess;
};
-saml::IPlugIn* ApacheRequestMapFactory(const DOMElement* e)
+RequestMapper* ApacheRequestMapFactory(const DOMElement* const & e)
{
return new ApacheRequestMapper(e);
}
ApacheRequestMapper::ApacheRequestMapper(const DOMElement* e) : m_mapper(NULL), m_staKey(NULL), m_propsKey(NULL), m_htaccess(NULL)
{
- saml::IPlugIn* p=saml::SAMLConfig::getConfig().getPlugMgr().newPlugin(XML_REQUESTMAP_PROVIDER,e);
- m_mapper=dynamic_cast<IRequestMapper*>(p);
- if (!m_mapper) {
- delete p;
- throw saml::UnsupportedExtensionException("Embedded request mapper plugin was not of correct type.");
- }
+ m_mapper=SPConfig::getConfig().RequestMapperManager.newPlugin(XML_REQUEST_MAPPER,e);
m_htaccess=new htAccessControl();
m_staKey=ThreadKey::create(NULL);
m_propsKey=ThreadKey::create(NULL);
}
-IRequestMapper::Settings ApacheRequestMapper::getSettings(ShibTarget* st) const
+RequestMapper::Settings ApacheRequestMapper::getSettings(const SPRequest& request) const
{
- Settings s=m_mapper->getSettings(st);
- m_staKey->setData(dynamic_cast<ShibTargetApache*>(st));
+ Settings s=m_mapper->getSettings(request);
+ m_staKey->setData((void*)dynamic_cast<const ShibTargetApache*>(&request));
m_propsKey->setData((void*)s.first);
- return pair<const PropertySet*,IAccessControl*>(this,s.second ? s.second : m_htaccess);
+ return pair<const PropertySet*,AccessControl*>(this,s.second ? s.second : m_htaccess);
}
pair<bool,bool> ApacheRequestMapper::getBool(const char* name, const char* ns) const
{
- ShibTargetApache* sta=reinterpret_cast<ShibTargetApache*>(m_staKey->getData());
+ const ShibTargetApache* sta=reinterpret_cast<const ShibTargetApache*>(m_staKey->getData());
const PropertySet* s=reinterpret_cast<const PropertySet*>(m_propsKey->getData());
if (sta && !ns) {
// Override Apache-settable boolean properties.
pair<bool,const char*> ApacheRequestMapper::getString(const char* name, const char* ns) const
{
- ShibTargetApache* sta=reinterpret_cast<ShibTargetApache*>(m_staKey->getData());
+ const ShibTargetApache* sta=reinterpret_cast<const ShibTargetApache*>(m_staKey->getData());
const PropertySet* s=reinterpret_cast<const PropertySet*>(m_propsKey->getData());
if (sta && !ns) {
// Override Apache-settable string properties.
pair<bool,unsigned int> ApacheRequestMapper::getUnsignedInt(const char* name, const char* ns) const
{
- ShibTargetApache* sta=reinterpret_cast<ShibTargetApache*>(m_staKey->getData());
+ const ShibTargetApache* sta=reinterpret_cast<const ShibTargetApache*>(m_staKey->getData());
const PropertySet* s=reinterpret_cast<const PropertySet*>(m_propsKey->getData());
if (sta && !ns) {
// Override Apache-settable int properties.
pair<bool,int> ApacheRequestMapper::getInt(const char* name, const char* ns) const
{
- ShibTargetApache* sta=reinterpret_cast<ShibTargetApache*>(m_staKey->getData());
+ const ShibTargetApache* sta=reinterpret_cast<const ShibTargetApache*>(m_staKey->getData());
const PropertySet* s=reinterpret_cast<const PropertySet*>(m_propsKey->getData());
if (sta && !ns) {
// Override Apache-settable int properties.
return grps;
}
-bool htAccessControl::authorized(
- ShibTarget* st,
- ISessionCacheEntry* entry
-) const
+bool htAccessControl::authorized(SPRequest& request, Session* session) const
{
// Make sure the object is our type.
- ShibTargetApache* sta=dynamic_cast<ShibTargetApache*>(st);
+ ShibTargetApache* sta=dynamic_cast<ShibTargetApache*>(&request);
if (!sta)
throw ConfigurationException("Request wrapper object was not of correct type.");
if (!(reqs[x].method_mask & (1 << m)))
continue;
method_restricted=true;
- string remote_user = st->getRemoteUser();
+ string remote_user = request.getRemoteUser();
t = reqs[x].requirement;
w = ap_getword_white(sta->m_req->pool, &t);
SHIB_AP_CHECK_IS_OK;
}
else if (!strcmp(w,"valid-user")) {
- if (entry) {
- st->log(ShibTarget::LogLevelDebug,"htAccessControl plugin accepting valid-user based on active session");
+ if (session) {
+ request.log(SPRequest::SPDebug,"htAccessControl plugin accepting valid-user based on active session");
SHIB_AP_CHECK_IS_OK;
}
else
- st->log(ShibTarget::LogLevelError,"htAccessControl plugin rejecting access for valid-user rule, no session is active");
+ request.log(SPRequest::SPError,"htAccessControl plugin rejecting access for valid-user rule, no session is active");
}
else if (!strcmp(w,"user") && !remote_user.empty()) {
bool regexp=false;
RegularExpression re(trans.get());
auto_ptr<XMLCh> trans2(fromUTF8(remote_user.c_str()));
if (re.matches(trans2.get())) {
- st->log(ShibTarget::LogLevelDebug, string("htAccessControl plugin accepting user (") + w + ")");
+ request.log(SPRequest::SPDebug, string("htAccessControl plugin accepting user (") + w + ")");
SHIB_AP_CHECK_IS_OK;
}
}
catch (XMLException& ex) {
auto_ptr_char tmp(ex.getMessage());
- st->log(ShibTarget::LogLevelError,
+ request.log(SPRequest::SPError,
string("htAccessControl plugin caught exception while parsing regular expression (") + w + "): " + tmp.get());
}
}
else if (remote_user==w) {
- st->log(ShibTarget::LogLevelDebug, string("htAccessControl plugin accepting user (") + w + ")");
+ request.log(SPRequest::SPDebug, string("htAccessControl plugin accepting user (") + w + ")");
SHIB_AP_CHECK_IS_OK;
}
}
else if (!strcmp(w,"group")) {
SH_AP_TABLE* grpstatus=NULL;
if (sta->m_dc->szAuthGrpFile && !remote_user.empty()) {
- st->log(ShibTarget::LogLevelDebug,string("htAccessControl plugin using groups file: ") + sta->m_dc->szAuthGrpFile);
+ request.log(SPRequest::SPDebug,string("htAccessControl plugin using groups file: ") + sta->m_dc->szAuthGrpFile);
grpstatus=groups_for_user(sta->m_req,remote_user.c_str(),sta->m_dc->szAuthGrpFile);
}
if (!grpstatus)
while (*t) {
w=ap_getword_conf(sta->m_req->pool,&t);
if (ap_table_get(grpstatus,w)) {
- st->log(ShibTarget::LogLevelDebug, string("htAccessControl plugin accepting group (") + w + ")");
+ request.log(SPRequest::SPDebug, string("htAccessControl plugin accepting group (") + w + ")");
SHIB_AP_CHECK_IS_OK;
}
}
}
else {
- saml::Iterator<shibboleth::IAAP*> provs=st->getApplication()->getAAPProviders();
+ saml::Iterator<shibboleth::IAAP*> provs=dynamic_cast<const IApplication&>(request.getSPApplication()).getAAPProviders();
shibboleth::AAP wrapper(provs,w);
if (wrapper.fail()) {
- st->log(ShibTarget::LogLevelWarn, string("htAccessControl plugin didn't recognize require rule: ") + w);
+ request.log(SPRequest::SPWarn, string("htAccessControl plugin didn't recognize require rule: ") + w);
continue;
}
for (unsigned int i = 0; i < vals_str.length(); i++) {
if (vals_str.at(i) == ';') {
if (i == 0) {
- st->log(ShibTarget::LogLevelError, string("htAccessControl plugin found invalid header encoding (") +
+ request.log(SPRequest::SPError, string("htAccessControl plugin found invalid header encoding (") +
vals + "): starts with a semicolon");
throw saml::SAMLException("Invalid information supplied to authorization plugin.");
}
if (regexp) {
auto_ptr<XMLCh> trans(fromUTF8(val.c_str()));
if (re->matches(trans.get())) {
- st->log(ShibTarget::LogLevelDebug, string("htAccessControl plugin expecting ") + w +
+ request.log(SPRequest::SPDebug, string("htAccessControl plugin expecting ") + w +
", got " + val + ": authorization granted");
SHIB_AP_CHECK_IS_OK;
}
}
else if ((wrapper->getCaseSensitive() && val==w) || (!wrapper->getCaseSensitive() && !strcasecmp(val.c_str(),w))) {
- st->log(ShibTarget::LogLevelDebug, string("htAccessControl plugin expecting ") + w +
+ request.log(SPRequest::SPDebug, string("htAccessControl plugin expecting ") + w +
", got " + val + ": authorization granted.");
SHIB_AP_CHECK_IS_OK;
}
else {
- st->log(ShibTarget::LogLevelDebug, string("htAccessControl plugin expecting ") + w +
+ request.log(SPRequest::SPDebug, string("htAccessControl plugin expecting ") + w +
", got " + val + ": authoritzation not granted.");
}
}
if (regexp) {
auto_ptr<XMLCh> trans(fromUTF8(val.c_str()));
if (re->matches(trans.get())) {
- st->log(ShibTarget::LogLevelDebug, string("htAccessControl plugin expecting ") + w +
+ request.log(SPRequest::SPDebug, string("htAccessControl plugin expecting ") + w +
", got " + val + ": authorization granted.");
SHIB_AP_CHECK_IS_OK;
}
}
else if ((wrapper->getCaseSensitive() && val==w) || (!wrapper->getCaseSensitive() && !strcasecmp(val.c_str(),w))) {
- st->log(ShibTarget::LogLevelDebug, string("htAccessControl plugin expecting ") + w +
+ request.log(SPRequest::SPDebug, string("htAccessControl plugin expecting ") + w +
", got " + val + ": authorization granted");
SHIB_AP_CHECK_IS_OK;
}
else {
- st->log(ShibTarget::LogLevelDebug, string("htAccessControl plugin expecting ") + w +
+ request.log(SPRequest::SPDebug, string("htAccessControl plugin expecting ") + w +
", got " + val + ": authorization not granted");
}
}
catch (XMLException& ex) {
auto_ptr_char tmp(ex.getMessage());
- st->log(ShibTarget::LogLevelError, string("htAccessControl plugin caught exception while parsing regular expression (")
+ request.log(SPRequest::SPError, string("htAccessControl plugin caught exception while parsing regular expression (")
+ w + "): " + tmp.get());
}
}
g_Config->shutdown();
g_Config = NULL;
}
- ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,NULL,"shib_exit() done\n");
+ ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,NULL,"shib_exit() done");
return OK;
}
#endif
{
shib_request_config* rc = init_request_config(r);
- ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r), "shib_post_read: E=%s\n", rc->env?"env":"hdr");
+ ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r), "shib_post_read: E=%s", rc->env?"env":"hdr");
#ifdef SHIB_DEFERRED_HEADERS
rc->hdr_out = ap_make_table(r->pool, 5);
if (dc->bOff==1 || dc->bUseEnvVars==0)
return DECLINED;
- ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r), "shib_fixup(%d): ENTER\n", (int)getpid());
+ ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r), "shib_fixup(%d): ENTER", (int)getpid());
if (rc==NULL || rc->env==NULL || ap_is_empty_table(rc->env))
return DECLINED;
- ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r), "shib_fixup adding %d vars\n", ap_table_elts(rc->env)->nelts);
+ ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r), "shib_fixup adding %d vars", ap_table_elts(rc->env)->nelts);
r->subprocess_env = ap_overlay_tables(r->pool, r->subprocess_env, rc->env);
return OK;
ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(s),"shib_child_exit(%d) dealing with g_Config..", (int)getpid());
g_Config->shutdown();
g_Config = NULL;
- ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(s),"shib_child_exit() done\n");
+ ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(s),"shib_child_exit() done");
#ifndef SHIB_APACHE_13
return OK;
SPConfig::Listener |
SPConfig::Metadata |
SPConfig::AAP |
- SPConfig::RequestMapper |
+ SPConfig::RequestMapping |
SPConfig::InProcess |
SPConfig::Logging
);
ap_log_error(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,SH_AP_R(s),"shib_child_init() failed to initialize libraries");
exit(1);
}
- saml::SAMLConfig::getConfig().getPlugMgr().regFactory(HTACCESS_ACCESSCONTROL,&htAccessFactory);
- saml::SAMLConfig::getConfig().getPlugMgr().regFactory(NATIVE_REQUESTMAP_PROVIDER,&ApacheRequestMapFactory);
- // We hijack the legacy type so that 1.2 config files will load this plugin
- saml::SAMLConfig::getConfig().getPlugMgr().regFactory(LEGACY_REQUESTMAP_PROVIDER,&ApacheRequestMapFactory);
+ SPConfig::getConfig().AccessControlManager.registerFactory(HT_ACCESS_CONTROL,&htAccessFactory);
+ SPConfig::getConfig().RequestMapperManager.registerFactory(NATIVE_REQUEST_MAPPER,&ApacheRequestMapFactory);
if (!g_Config->load(g_szSHIBConfig)) {
ap_log_error(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,SH_AP_R(s),"shib_child_init() failed to load configuration");
#define ap_pstrcat apr_pstrcat
#define ap_psprintf apr_psprintf
#define ap_table_get apr_table_get
+#define ap_table_add apr_table_add
#define ap_table_addn apr_table_addn
#define ap_table_setn apr_table_setn
#define ap_table_unset apr_table_unset
#define ap_pstrcat apr_pstrcat
#define ap_psprintf apr_psprintf
#define ap_table_get apr_table_get
+#define ap_table_add apr_table_add
#define ap_table_addn apr_table_addn
#define ap_table_setn apr_table_setn
#define ap_table_unset apr_table_unset
* limitations under the License.
*/
-/* isapi_shib.cpp - Shibboleth ISAPI filter
-
- Scott Cantor
- 8/23/02
-*/
+/**
+ * isapi_shib.cpp
+ *
+ * Shibboleth ISAPI filter
+ */
#include "config_win32.h"
#define _CRT_SECURE_NO_DEPRECATE 1
#include <shibsp/SPConfig.h>
+#include <xmltooling/util/NDC.h>
// SAML Runtime
#include <saml/saml.h>
#include <shib/shib.h>
#include <shib-target/shib-target.h>
-#include <ctime>
-#include <fstream>
#include <sstream>
-#include <stdexcept>
+#include <fstream>
#include <process.h>
#include <httpfilt.h>
// globals
namespace {
- static const XMLCh name[] = { chLatin_n, chLatin_a, chLatin_m, chLatin_e, chNull };
- static const XMLCh port[] = { chLatin_p, chLatin_o, chLatin_r, chLatin_t, chNull };
- static const XMLCh sslport[] = { chLatin_s, chLatin_s, chLatin_l, chLatin_p, chLatin_o, chLatin_r, chLatin_t, chNull };
- static const XMLCh scheme[] = { chLatin_s, chLatin_c, chLatin_h, chLatin_e, chLatin_m, chLatin_e, chNull };
- static const XMLCh id[] = { chLatin_i, chLatin_d, 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 };
- static const XMLCh ISAPI[] = { chLatin_I, chLatin_S, chLatin_A, chLatin_P, chLatin_I, chNull };
- static const XMLCh Alias[] = { chLatin_A, chLatin_l, chLatin_i, chLatin_a, chLatin_s, chNull };
+ static const XMLCh name[] = UNICODE_LITERAL_4(n,a,m,e);
+ static const XMLCh port[] = UNICODE_LITERAL_4(p,o,r,t);
+ static const XMLCh sslport[] = UNICODE_LITERAL_7(s,s,l,p,o,r,t);
+ static const XMLCh scheme[] = UNICODE_LITERAL_6(s,c,h,e,m,e);
+ static const XMLCh id[] = UNICODE_LITERAL_2(i,d);
+ static const XMLCh Implementation[] = UNICODE_LITERAL_14(I,m,p,l,e,m,e,n,t,a,t,i,o,n);
+ static const XMLCh ISAPI[] = UNICODE_LITERAL_5(I,S,A,P,I);
+ static const XMLCh Alias[] = UNICODE_LITERAL_5(A,l,i,a,s);
static const XMLCh normalizeRequest[] = UNICODE_LITERAL_16(n,o,r,m,a,l,i,z,e,R,e,q,u,e,s,t);
static const XMLCh Site[] = UNICODE_LITERAL_4(S,i,t,e);
if (!pVer)
return FALSE;
- if (!g_Config)
- {
+ if (!g_Config) {
LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL,
"Extension mode startup not possible, is the DLL loaded as a filter?");
return FALSE;
SPConfig::Caching |
SPConfig::Metadata |
SPConfig::AAP |
- SPConfig::RequestMapper |
+ SPConfig::RequestMapping |
SPConfig::InProcess |
SPConfig::Logging
);
}
void GetServerVariable(PHTTP_FILTER_CONTEXT pfc, LPSTR lpszVariable, dynabuf& s, DWORD size=80, bool bRequired=true)
- throw (bad_alloc, DWORD)
{
s.reserve(size);
s.erase();
size=s.size();
- while (!pfc->GetServerVariable(pfc,lpszVariable,s,&size))
- {
+ while (!pfc->GetServerVariable(pfc,lpszVariable,s,&size)) {
// Grumble. Check the error.
DWORD e=GetLastError();
if (e==ERROR_INSUFFICIENT_BUFFER)
}
void GetServerVariable(LPEXTENSION_CONTROL_BLOCK lpECB, LPSTR lpszVariable, dynabuf& s, DWORD size=80, bool bRequired=true)
- throw (bad_alloc, DWORD)
{
s.reserve(size);
s.erase();
size=s.size();
- while (!lpECB->GetServerVariable(lpECB->ConnID,lpszVariable,s,&size))
- {
+ while (!lpECB->GetServerVariable(lpECB->ConnID,lpszVariable,s,&size)) {
// Grumble. Check the error.
DWORD e=GetLastError();
if (e==ERROR_INSUFFICIENT_BUFFER)
void GetHeader(PHTTP_FILTER_PREPROC_HEADERS pn, PHTTP_FILTER_CONTEXT pfc,
LPSTR lpszName, dynabuf& s, DWORD size=80, bool bRequired=true)
- throw (bad_alloc, DWORD)
{
s.reserve(size);
s.erase();
size=s.size();
- while (!pn->GetHeader(pfc,lpszName,s,&size))
- {
+ while (!pn->GetHeader(pfc,lpszName,s,&size)) {
// Grumble. Check the error.
DWORD e=GetLastError();
if (e==ERROR_INSUFFICIENT_BUFFER)
{
PHTTP_FILTER_CONTEXT m_pfc;
PHTTP_FILTER_PREPROC_HEADERS m_pn;
- string m_cookie;
+ map<string,string> m_headers;
+ vector<XSECCryptoX509*> m_certs;
+
public:
ShibTargetIsapiF(PHTTP_FILTER_CONTEXT pfc, PHTTP_FILTER_PREPROC_HEADERS pn, const site_t& site) {
+ m_pfc = pfc;
+ m_pn = pn;
+
// URL path always come from IIS.
dynabuf url(256);
GetHeader(pn,pfc,"url",url,256,false);
host=site.m_name.c_str();
init(scheme, host, atoi(port), url, content_type, remote_addr, method);
-
- m_pfc = pfc;
- m_pn = pn;
}
~ShibTargetIsapiF() { }
- virtual void log(ShibLogLevel level, const string &msg) {
- ShibTarget::log(level,msg);
- if (level == LogLevelError)
- LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, msg.c_str());
+ const char* getScheme() const {
+ return m_scheme.c_str();
}
- virtual string getCookies() const {
- dynabuf buf(128);
- GetHeader(m_pn, m_pfc, "Cookie:", buf, 128, false);
- return buf.empty() ? "" : buf;
+ const char* getHostname() const {
+ return m_hostname.c_str();
}
-
- virtual void clearHeader(const string &name) {
- string hdr = (name=="REMOTE_USER" ? "remote-user" : name) + ":";
+ int getPort() const {
+ return m_port;
+ }
+ const char* getRequestURI() const {
+ return m_uri.c_str();
+ }
+ const char* getMethod() const {
+ return m_method.c_str();
+ }
+ string getContentType() const {
+ return m_content_type;
+ }
+ long getContentLength() const {
+ return 0;
+ }
+ string getRemoteAddr() const {
+ return m_remote_addr;
+ }
+ void log(SPLogLevel level, const string& msg) {
+ AbstractSPRequest::log(level,msg);
+ if (level >= SPError)
+ LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, msg.c_str());
+ }
+ void clearHeader(const char* name) {
+ string hdr(!strcmp(name,"REMOTE_USER") ? "remote-user" : name);
+ hdr += ':';
m_pn->SetHeader(m_pfc, const_cast<char*>(hdr.c_str()), "");
}
- virtual void setHeader(const string &name, const string &value) {
- string hdr = name + ":";
- m_pn->SetHeader(m_pfc, const_cast<char*>(hdr.c_str()),
- const_cast<char*>(value.c_str()));
+ void setHeader(const char* name, const char* value) {
+ string hdr(name);
+ hdr += ':';
+ m_pn->SetHeader(m_pfc, const_cast<char*>(hdr.c_str()), const_cast<char*>(value));
}
- virtual string getHeader(const string &name) {
- string hdr = name + ":";
+ string getHeader(const char* name) const {
+ string hdr(name);
+ hdr += ':';
dynabuf buf(1024);
GetHeader(m_pn, m_pfc, const_cast<char*>(hdr.c_str()), buf, 1024, false);
return string(buf);
}
- virtual void setRemoteUser(const string &user) {
- setHeader(string("remote-user"), user);
+ void setRemoteUser(const char* user) {
+ setHeader("remote-user", user);
}
- virtual string getRemoteUser(void) {
- return getHeader(string("remote-user"));
+ string getRemoteUser() const {
+ return getHeader("remote-user");
}
- virtual void* sendPage(
- const string& msg,
- int code=200,
- const string& content_type="text/html",
- const saml::Iterator<header_t>& headers=EMPTY(header_t)) {
- string hdr = string ("Connection: close\r\nContent-type: ") + content_type + "\r\n";
- while (headers.hasNext()) {
- const header_t& h=headers.next();
- hdr += h.first + ": " + h.second + "\r\n";
- }
+ void setResponseHeader(const char* name, const char* value) {
+ // Set for later.
+ if (value)
+ m_headers[name] = value;
+ else
+ m_headers.erase(name);
+ }
+ long sendResponse(istream& in, long status) {
+ string hdr = string("Connection: close\r\n");
+ for (map<string,string>::const_iterator i=m_headers.begin(); i!=m_headers.end(); ++i)
+ hdr += i->first + ": " + i->second + "\r\n";
hdr += "\r\n";
const char* codestr="200 OK";
- switch (code) {
- case 403: codestr="403 Forbidden"; break;
- case 404: codestr="404 Not Found"; break;
- case 500: codestr="500 Server Error"; break;
+ switch (status) {
+ case SAML_HTTP_STATUS_FORBIDDEN:codestr="403 Forbidden"; break;
+ case SAML_HTTP_STATUS_NOTFOUND: codestr="404 Not Found"; break;
+ case SAML_HTTP_STATUS_ERROR: codestr="500 Server Error"; break;
}
m_pfc->ServerSupportFunction(m_pfc, SF_REQ_SEND_RESPONSE_HEADER, (void*)codestr, (DWORD)hdr.c_str(), 0);
- DWORD resplen = msg.size();
- m_pfc->WriteClient(m_pfc, (LPVOID)msg.c_str(), &resplen, 0);
- return (void*)SF_STATUS_REQ_FINISHED;
+ char buf[1024];
+ while (in) {
+ in.read(buf,1024);
+ DWORD resplen = in.gcount();
+ m_pfc->WriteClient(m_pfc, buf, &resplen, 0);
+ }
+ return SF_STATUS_REQ_FINISHED;
}
- virtual void* sendRedirect(const string& url) {
+ long sendRedirect(const char* url) {
// XXX: Don't support the httpRedirect option, yet.
- string hdrs=m_cookie + string("Location: ") + url + "\r\n"
+ string hdr=string("Location: ") + url + "\r\n"
"Content-Type: text/html\r\n"
"Content-Length: 40\r\n"
"Expires: 01-Jan-1997 12:00:00 GMT\r\n"
- "Cache-Control: private,no-store,no-cache\r\n\r\n";
- m_pfc->ServerSupportFunction(m_pfc, SF_REQ_SEND_RESPONSE_HEADER,
- "302 Please Wait", (DWORD)hdrs.c_str(), 0);
+ "Cache-Control: private,no-store,no-cache\r\n";
+ for (map<string,string>::const_iterator i=m_headers.begin(); i!=m_headers.end(); ++i)
+ hdr += i->first + ": " + i->second + "\r\n";
+ hdr += "\r\n";
+ m_pfc->ServerSupportFunction(m_pfc, SF_REQ_SEND_RESPONSE_HEADER, "302 Please Wait", (DWORD)hdr.c_str(), 0);
static const char* redmsg="<HTML><BODY>Redirecting...</BODY></HTML>";
DWORD resplen=40;
m_pfc->WriteClient(m_pfc, (LPVOID)redmsg, &resplen, 0);
- return reinterpret_cast<void*>(SF_STATUS_REQ_FINISHED);
+ return SF_STATUS_REQ_FINISHED;
}
// XXX: We might not ever hit the 'decline' status in this filter.
- //virtual void* returnDecline(void) { }
- virtual void* returnOK(void) { return (void*) SF_STATUS_REQ_NEXT_NOTIFICATION; }
+ //long returnDecline(void) { }
+ long returnOK(void) {
+ return SF_STATUS_REQ_NEXT_NOTIFICATION;
+ }
- // The filter never processes the POST, so stub these methods.
- virtual void setCookie(const string &name, const string &value) {
- // Set the cookie for later. Use it during the redirect.
- m_cookie += "Set-Cookie: " + name + "=" + value + "\r\n";
+ const vector<XSECCryptoX509*>& getClientCertificates() const {
+ return m_certs;
}
- virtual const char* getQueryString() const { throw runtime_error("getQueryString not implemented"); }
- virtual const char* getRequestBody() const { throw runtime_error("getRequestBody not implemented"); }
+
+ // The filter never processes the POST, so stub these methods.
+ const char* getQueryString() const { throw runtime_error("getQueryString not implemented"); }
+ const char* getRequestBody() const { throw runtime_error("getRequestBody not implemented"); }
};
DWORD WriteClientError(PHTTP_FILTER_CONTEXT pfc, const char* msg)
ostringstream threadid;
threadid << "[" << getpid() << "] isapi_shib" << '\0';
- saml::NDC ndc(threadid.str().c_str());
+ xmltooling::NDC ndc(threadid.str().c_str());
ShibTargetIsapiF stf(pfc, pn, map_i->second);
// "false" because we don't override the Shib settings
- pair<bool,void*> res = stf.doCheckAuthN();
- if (res.first) return (DWORD)res.second;
+ pair<bool,long> res = stf.doCheckAuthN();
+ if (res.first) return res.second;
// "false" because we don't override the Shib settings
res = stf.doExportAssertions();
- if (res.first) return (DWORD)res.second;
+ if (res.first) return res.second;
res = stf.doCheckAuthZ();
- if (res.first) return (DWORD)res.second;
+ if (res.first) return res.second;
return SF_STATUS_REQ_NEXT_NOTIFICATION;
}
else
return WriteClientError(pfc,"Shibboleth Filter detected unexpected IIS error.");
}
- catch (saml::SAMLException& e) {
+ catch (exception& e) {
LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, e.what());
return WriteClientError(pfc,"Shibboleth Filter caught an exception, check Event Log for details.");
}
class ShibTargetIsapiE : public ShibTarget
{
LPEXTENSION_CONTROL_BLOCK m_lpECB;
- string m_cookie;
+ map<string,string> m_headers;
+ vector<XSECCryptoX509*> m_certs;
mutable string m_body;
mutable bool m_gotBody;
public:
- ShibTargetIsapiE(LPEXTENSION_CONTROL_BLOCK lpECB, const site_t& site) : m_gotBody(false) {
+ ShibTargetIsapiE(LPEXTENSION_CONTROL_BLOCK lpECB, const site_t& site) : m_lpECB(lpECB), m_gotBody(false) {
dynabuf ssl(5);
GetServerVariable(lpECB,"HTTPS",ssl,5);
bool SSL=(ssl=="on" || ssl=="ON");
fullurl+=lpECB->lpszQueryString;
}
init(scheme, host, atoi(port), fullurl.c_str(), lpECB->lpszContentType, remote_addr, lpECB->lpszMethod);
-
- m_lpECB = lpECB;
}
~ShibTargetIsapiE() { }
- virtual void log(ShibLogLevel level, const string &msg) {
- ShibTarget::log(level,msg);
- if (level == LogLevelError)
+ const char* getScheme() const {
+ return m_scheme.c_str();
+ }
+ const char* getHostname() const {
+ return m_hostname.c_str();
+ }
+ int getPort() const {
+ return m_port;
+ }
+ const char* getRequestURI() const {
+ return m_uri.c_str();
+ }
+ const char* getMethod() const {
+ return m_lpECB->lpszMethod ? m_lpECB->lpszMethod : "";
+ }
+ string getContentType() const {
+ return m_lpECB->lpszContentType ? m_lpECB->lpszContentType : "";
+ }
+ long getContentLength() const {
+ return m_lpECB->cbTotalBytes;
+ }
+ string getRemoteAddr() const {
+ return m_remote_addr;
+ }
+ void log(SPLogLevel level, const string& msg) {
+ AbstractSPRequest::log(level,msg);
+ if (level >= SPError)
LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, msg.c_str());
}
- virtual string getCookies() const {
+ string getHeader(const char* name) const {
+ string hdr("HTTP_");
+ for (; *name; ++name) {
+ if (*name=='-')
+ hdr += '_';
+ else
+ hdr += toupper(*name);
+ }
dynabuf buf(128);
- GetServerVariable(m_lpECB, "HTTP_COOKIE", buf, 128, false);
+ GetServerVariable(m_lpECB, const_cast<char*>(hdr.c_str()), buf, 128, false);
return buf.empty() ? "" : buf;
}
- virtual void setCookie(const string &name, const string &value) {
- // Set the cookie for later. Use it during the redirect.
- m_cookie += "Set-Cookie: " + name + "=" + value + "\r\n";
+ void setResponseHeader(const char* name, const char* value) {
+ // Set for later.
+ if (value)
+ m_headers[name] = value;
+ else
+ m_headers.erase(name);
}
- virtual const char* getQueryString() const {
+ const char* getQueryString() const {
return m_lpECB->lpszQueryString;
}
- virtual const char* getRequestBody() const {
+ const char* getRequestBody() const {
if (m_gotBody)
return m_body.c_str();
if (m_lpECB->cbTotalBytes > 1024*1024) // 1MB?
- throw saml::SAMLException("Size of POST request body exceeded limit.");
+ throw opensaml::BindingException("Size of POST request body exceeded limit.");
else if (m_lpECB->cbTotalBytes != m_lpECB->cbAvailable) {
m_gotBody=true;
char buf[8192];
}
return m_body.c_str();
}
- virtual void* sendPage(
- const string &msg,
- int code=200,
- const string& content_type="text/html",
- const saml::Iterator<header_t>& headers=EMPTY(header_t)) {
- string hdr = string ("Connection: close\r\nContent-type: ") + content_type + "\r\n";
- for (unsigned int k = 0; k < headers.size(); k++) {
- hdr += headers[k].first + ": " + headers[k].second + "\r\n";
- }
+ long sendResponse(istream& in, long status) {
+ string hdr = string("Connection: close\r\n");
+ for (map<string,string>::const_iterator i=m_headers.begin(); i!=m_headers.end(); ++i)
+ hdr += i->first + ": " + i->second + "\r\n";
hdr += "\r\n";
const char* codestr="200 OK";
- switch (code) {
- case 403: codestr="403 Forbidden"; break;
- case 404: codestr="404 Not Found"; break;
- case 500: codestr="500 Server Error"; break;
+ switch (status) {
+ case SAML_HTTP_STATUS_FORBIDDEN:codestr="403 Forbidden"; break;
+ case SAML_HTTP_STATUS_NOTFOUND: codestr="404 Not Found"; break;
+ case SAML_HTTP_STATUS_ERROR: codestr="500 Server Error"; break;
}
m_lpECB->ServerSupportFunction(m_lpECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, (void*)codestr, 0, (LPDWORD)hdr.c_str());
- DWORD resplen = msg.size();
- m_lpECB->WriteClient(m_lpECB->ConnID, (LPVOID)msg.c_str(), &resplen, HSE_IO_SYNC);
- return (void*)HSE_STATUS_SUCCESS;
+ char buf[1024];
+ while (in) {
+ in.read(buf,1024);
+ DWORD resplen = in.gcount();
+ m_lpECB->WriteClient(m_lpECB->ConnID, buf, &resplen, HSE_IO_SYNC);
+ }
+ return HSE_STATUS_SUCCESS;
}
- virtual void* sendRedirect(const string& url) {
- // XXX: Don't support the httpRedirect option, yet.
- string hdrs = m_cookie + "Location: " + url + "\r\n"
+ long sendRedirect(const char* url) {
+ string hdr=string("Location: ") + url + "\r\n"
"Content-Type: text/html\r\n"
"Content-Length: 40\r\n"
"Expires: 01-Jan-1997 12:00:00 GMT\r\n"
- "Cache-Control: private,no-store,no-cache\r\n\r\n";
- m_lpECB->ServerSupportFunction(m_lpECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER,
- "302 Moved", 0, (LPDWORD)hdrs.c_str());
+ "Cache-Control: private,no-store,no-cache\r\n";
+ for (map<string,string>::const_iterator i=m_headers.begin(); i!=m_headers.end(); ++i)
+ hdr += i->first + ": " + i->second + "\r\n";
+ hdr += "\r\n";
+ m_lpECB->ServerSupportFunction(m_lpECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, "302 Moved", 0, (LPDWORD)hdr.c_str());
static const char* redmsg="<HTML><BODY>Redirecting...</BODY></HTML>";
DWORD resplen=40;
m_lpECB->WriteClient(m_lpECB->ConnID, (LPVOID)redmsg, &resplen, HSE_IO_SYNC);
- return (void*)HSE_STATUS_SUCCESS;
+ return HSE_STATUS_SUCCESS;
}
// Decline happens in the POST processor if this isn't the shire url
// Note that it can also happen with HTAccess, but we don't support that, yet.
- virtual void* returnDecline(void) {
- return (void*)
- WriteClientError(m_lpECB, "ISAPI extension can only be invoked to process Shibboleth protocol requests."
- "Make sure the mapped file extension doesn't match actual content.");
+ long returnDecline() {
+ return WriteClientError(
+ m_lpECB,
+ "ISAPI extension can only be invoked to process Shibboleth protocol requests."
+ "Make sure the mapped file extension doesn't match actual content."
+ );
+ }
+ long returnOK() {
+ return HSE_STATUS_SUCCESS;
+ }
+
+ const vector<XSECCryptoX509*>& getClientCertificates() const {
+ return m_certs;
}
- virtual void* returnOK(void) { return (void*) HSE_STATUS_SUCCESS; }
// Not used in the extension.
- virtual void clearHeader(const string &name) { throw runtime_error("clearHeader not implemented"); }
- virtual void setHeader(const string &name, const string &value) { throw runtime_error("setHeader not implemented"); }
- virtual string getHeader(const string &name) { throw runtime_error("getHeader not implemented"); }
- virtual void setRemoteUser(const string &user) { throw runtime_error("setRemoteUser not implemented"); }
- virtual string getRemoteUser(void) { throw runtime_error("getRemoteUser not implemented"); }
+ virtual void clearHeader(const char* name) { throw runtime_error("clearHeader not implemented"); }
+ virtual void setHeader(const char* name, const char* value) { throw runtime_error("setHeader not implemented"); }
+ virtual void setRemoteUser(const char* user) { throw runtime_error("setRemoteUser not implemented"); }
+ virtual string getRemoteUser() const { throw runtime_error("getRemoteUser not implemented"); }
};
extern "C" DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB)
try {
ostringstream threadid;
threadid << "[" << getpid() << "] isapi_shib_extension" << '\0';
- saml::NDC ndc(threadid.str().c_str());
+ xmltooling::NDC ndc(threadid.str().c_str());
// Determine web site number. This can't really fail, I don't think.
dynabuf buf(128);
return WriteClientError(lpECB, "Shibboleth Extension not configured for this web site.");
ShibTargetIsapiE ste(lpECB, map_i->second);
- pair<bool,void*> res = ste.doHandler();
- if (res.first) return (DWORD)res.second;
+ pair<bool,long> res = ste.doHandler();
+ if (res.first) return res.second;
return WriteClientError(lpECB, "Shibboleth Extension failed to process request");
else
return WriteClientError(lpECB,"Server detected unexpected IIS error.");
}
- catch (saml::SAMLException& e) {
+ catch (exception& e) {
LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, e.what());
return WriteClientError(lpECB,"Shibboleth Extension caught an exception, check Event Log for details.");
}
* limitations under the License.
*/
-/* nsapi_shib.cpp - Shibboleth NSAPI filter
-
- Scott Cantor
- 12/13/04
-*/
+/**
+ * nsapi_shib.cpp
+ *
+ * Shibboleth NSAPI filter
+ */
#if defined (_MSC_VER) || defined(__BORLANDC__)
# include "config_win32.h"
# define _CRT_SECURE_NO_DEPRECATE 1
#endif
+#include <shibsp/RequestMapper.h>
#include <shibsp/SPConfig.h>
+#include <xmltooling/util/NDC.h>
#include <xmltooling/util/Threads.h>
// SAML Runtime
#include <shib/shib.h>
#include <shib-target/shib-target.h>
-#include <ctime>
#include <fstream>
#include <sstream>
-#include <stdexcept>
#ifdef WIN32
# include <process.h>
using namespace shibsp;
using namespace shibtarget;
-using namespace saml;
using namespace xmltooling;
using namespace std;
ShibTargetConfig* g_Config=NULL;
string g_ServerName;
string g_ServerScheme;
+ string g_unsetHeaderValue;
}
-PlugManager::Factory SunRequestMapFactory;
+PluginManager<RequestMapper,const DOMElement*>::Factory SunRequestMapFactory;
extern "C" NSAPI_PUBLIC void nsapi_shib_exit(void*)
{
SPConfig::Caching |
SPConfig::Metadata |
SPConfig::AAP |
- SPConfig::RequestMapper |
+ SPConfig::RequestMapping |
SPConfig::InProcess |
SPConfig::Logging
);
return REQ_ABORTED;
}
- SAMLConfig::getConfig().getPlugMgr().regFactory(NATIVE_REQUESTMAP_PROVIDER,&SunRequestMapFactory);
- // We hijack the legacy type so that 1.2 config files will load this plugin
- SAMLConfig::getConfig().getPlugMgr().regFactory(LEGACY_REQUESTMAP_PROVIDER,&SunRequestMapFactory);
+ SPConfig::getConfig().RequestMapperManager.registerFactory(XML_REQUEST_MAPPER,&SunRequestMapFactory);
if (!g_Config->load(config)) {
g_Config=NULL;
}
daemon_atrestart(nsapi_shib_exit,NULL);
+
+ IConfig* conf=g_Config->getINI();
+ Locker locker(conf);
+ const PropertySet* props=conf->getPropertySet("Local");
+ if (props) {
+ pair<bool,const char*> unsetValue=props->getString("unsetHeaderValue");
+ if (unsetValue.first)
+ g_unsetHeaderValue = unsetValue.second;
+ }
#ifndef _DEBUG
}
catch (...) {
class ShibTargetNSAPI : public ShibTarget
{
- mutable string m_body;
- mutable bool m_gotBody;
+ mutable string m_body;
+ mutable bool m_gotBody;
+ vector<XSECCryptoX509*> m_certs;
+
public:
ShibTargetNSAPI(pblock* pb, Session* sn, Request* rq) : m_gotBody(false) {
m_pb = pb;
}
~ShibTargetNSAPI() {}
- virtual void log(ShibLogLevel level, const string &msg) {
- ShibTarget::log(level,msg);
- if (level==LogLevelError)
- log_error(LOG_FAILURE, "nsapi_shib", m_sn, m_rq, const_cast<char*>(msg.c_str()));
+ const char* getScheme() const {
+ return security_active ? "https" : "http";
+ }
+ const char* getHostname() const {
+#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)
+ // The beauty here is, a non-default vhost can *only* be accessed if the client
+ // specified the exact name in the Host header. So we can trust the Host header.
+ return pblock_findval("host", m_rq->headers);
+ else
+#endif
+ // In other cases, we're going to rely on the initialization process...
+ return g_ServerName.c_str();
+ }
+ int getPort() const {
+ return server_portnum;
+ }
+ const char* getRequestURI() const {
+ return m_uri.c_str();
}
- virtual string getCookies(void) const {
- char *cookies = NULL;
- if (request_header("cookie", &cookies, m_sn, m_rq) == REQ_ABORTED)
- throw("error accessing cookie header");
- return string(cookies ? cookies : "");
+ const char* getMethod() const {
+ return pblock_findval("method", m_rq->reqpb);
}
- virtual void setCookie(const string &name, const string &value) {
- string cookie = name + '=' + value;
- pblock_nvinsert("Set-Cookie", cookie.c_str(), m_rq->srvhdrs);
+ string getContentType() const {
+ char* content_type = "";
+ request_header("content-type", &content_type, m_sn, m_rq);
+ return content_type;
+ }
+ long getContentLength() const {
+ if (m_gotBody)
+ return m_body.length();
+ char* content_length="";
+ request_header("content-length", &content_length, m_sn, m_rq);
+ return atoi(content_length);
}
- virtual const char* getQueryString() const {
+ string getRemoteAddr() const {
+ return pblock_findval("ip", m_sn->client);
+ }
+ void log(SPLogLevel level, const string& msg) {
+ AbstractSPRequest::log(level,msg);
+ if (level>=SPError)
+ log_error(LOG_FAILURE, "nsapi_shib", m_sn, m_rq, const_cast<char*>(msg.c_str()));
+ }
+ const char* getQueryString() const {
return pblock_findval("query", m_rq->reqpb);
}
- virtual const char* getRequestBody() const {
+ const char* getRequestBody() const {
if (m_gotBody)
return m_body.c_str();
char* content_length=NULL;
if (request_header("content-length", &content_length, m_sn, m_rq)!=REQ_PROCEED ||
atoi(content_length) > 1024*1024) // 1MB?
- throw SAMLException("Blocked POST request body exceeding size limit.");
+ throw opensaml::BindingException("Blocked POST request body exceeding size limit.");
else {
char ch=IO_EOF+1;
int cl=atoi(content_length);
cl--;
}
if (cl)
- throw SAMLException("Error reading POST request body from browser.");
+ throw opensaml::BindingException("Error reading POST request body from browser.");
return m_body.c_str();
}
}
- virtual void clearHeader(const string &name) {
- if (name=="REMOTE_USER") {
+ void clearHeader(const char* name) {
+ if (!strcmp(name,"REMOTE_USER")) {
param_free(pblock_remove("auth-user",m_rq->vars));
param_free(pblock_remove("remote-user",m_rq->headers));
}
- else
- param_free(pblock_remove(name.c_str(), m_rq->headers));
+ else {
+ param_free(pblock_remove(name, m_rq->headers));
+ pblock_nvinsert(name, g_unsetHeaderValue.c_str() ,m_rq->headers);
+ }
}
- virtual void setHeader(const string &name, const string &value) {
- pblock_nvinsert(name.c_str(), value.c_str() ,m_rq->headers);
+ void setHeader(const char* name, const char* value) {
+ pblock_nvinsert(name, value, m_rq->headers);
}
- virtual string getHeader(const string &name) {
- char *hdr = NULL;
- if (request_header(const_cast<char*>(name.c_str()), &hdr, m_sn, m_rq) != REQ_PROCEED)
+ string getHeader(const char* name) const {
+ char* hdr = NULL;
+ if (request_header(const_cast<char*>(name), &hdr, m_sn, m_rq) != REQ_PROCEED)
hdr = NULL;
return string(hdr ? hdr : "");
}
- virtual void setRemoteUser(const string &user) {
- pblock_nvinsert("remote-user", user.c_str(), m_rq->headers);
- pblock_nvinsert("auth-user", user.c_str(), m_rq->vars);
+ void setRemoteUser(const char* user) {
+ pblock_nvinsert("remote-user", user, m_rq->headers);
+ pblock_nvinsert("auth-user", user, m_rq->vars);
}
- virtual string getRemoteUser(void) {
+ string getRemoteUser() const {
return getHeader("remote-user");
}
+ void setResponseHeader(const char* name, const char* value) {
+ pblock_nvinsert(name, value, m_rq->srvhdrs);
+ }
- virtual void* sendPage(
- const string& msg,
- int code=200,
- const string& content_type="text/html",
- const saml::Iterator<header_t>& headers=EMPTY(header_t)
- ) {
- 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();
- pblock_nvinsert(h.first.c_str(), h.second.c_str(), m_rq->srvhdrs);
+ long sendResponse(istream& in, long status) {
+ string msg;
+ char buf[1024];
+ while (in) {
+ in.read(buf,1024);
+ msg.append(buf,in.gcount());
}
- protocol_status(m_sn, m_rq, code, NULL);
+ pblock_nvinsert("connection","close",m_rq->srvhdrs);
+ pblock_nninsert("content-length", msg.length(), m_rq->srvhdrs);
+ protocol_status(m_sn, m_rq, status, NULL);
protocol_start_response(m_sn, m_rq);
net_write(m_sn->csd,const_cast<char*>(msg.c_str()),msg.length());
- return (void*)REQ_EXIT;
+ return REQ_EXIT;
}
- virtual void* sendRedirect(const string& url) {
+ long sendRedirect(const char* url) {
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);
pblock_nvinsert("cache-control", "private,no-store,no-cache", m_rq->srvhdrs);
- pblock_nvinsert("location", url.c_str(), m_rq->srvhdrs);
+ pblock_nvinsert("location", url, m_rq->srvhdrs);
pblock_nvinsert("connection","close",m_rq->srvhdrs);
protocol_status(m_sn, m_rq, PROTOCOL_REDIRECT, NULL);
protocol_start_response(m_sn, m_rq);
- return (void*)REQ_ABORTED;
+ return REQ_ABORTED;
+ }
+ long returnDecline() { return REQ_NOACTION; }
+ long returnOK() { return REQ_PROCEED; }
+ const vector<XSECCryptoX509*>& getClientCertificates() const {
+ return m_certs;
}
- virtual void* returnDecline(void) { return (void*)REQ_NOACTION; }
- virtual void* returnOK(void) { return (void*)REQ_PROCEED; }
pblock* m_pb;
Session* m_sn;
{
ostringstream threadid;
threadid << "[" << getpid() << "] nsapi_shib" << '\0';
- saml::NDC ndc(threadid.str().c_str());
+ xmltooling::NDC ndc(threadid.str().c_str());
try {
ShibTargetNSAPI stn(pb, sn, rq);
// Check user authentication
- pair<bool,void*> res = stn.doCheckAuthN();
+ pair<bool,long> res = stn.doCheckAuthN();
if (res.first) return (int)res.second;
// user authN was okay -- export the assertions now
// this user is ok.
return REQ_PROCEED;
}
- catch (SAMLException& e) {
+ catch (exception& e) {
log_error(LOG_FAILURE,FUNC,sn,rq,const_cast<char*>(e.what()));
- return WriteClientError(sn, rq, FUNC, "Shibboleth filter threw an exception, see web server log for error.");
+ return WriteClientError(sn, rq, FUNC, "Shibboleth module threw an exception, see web server log for error.");
}
#ifndef _DEBUG
catch (...) {
- return WriteClientError(sn, rq, FUNC, "Shibboleth filter threw an uncaught exception.");
+ return WriteClientError(sn, rq, FUNC, "Shibboleth module threw an uncaught exception.");
}
#endif
}
{
ostringstream threadid;
threadid << "[" << getpid() << "] shib_handler" << '\0';
- saml::NDC ndc(threadid.str().c_str());
+ xmltooling::NDC ndc(threadid.str().c_str());
try {
ShibTargetNSAPI stn(pb, sn, rq);
- pair<bool,void*> res = stn.doHandler();
+ pair<bool,long> res = stn.doHandler();
if (res.first) return (int)res.second;
return WriteClientError(sn, rq, FUNC, "Shibboleth handler did not do anything.");
}
- catch (SAMLException& e) {
+ catch (exception& e) {
log_error(LOG_FAILURE,FUNC,sn,rq,const_cast<char*>(e.what()));
return WriteClientError(sn, rq, FUNC, "Shibboleth handler threw an exception, see web server log for error.");
}
}
-class SunRequestMapper : public virtual IRequestMapper, public virtual PropertySet
+class SunRequestMapper : public virtual RequestMapper, public virtual PropertySet
{
public:
SunRequestMapper(const DOMElement* e);
~SunRequestMapper() { delete m_mapper; delete m_stKey; delete m_propsKey; }
Lockable* lock() { return m_mapper->lock(); }
void unlock() { m_stKey->setData(NULL); m_propsKey->setData(NULL); m_mapper->unlock(); }
- Settings getSettings(ShibTarget* st) const;
+ Settings getSettings(const SPRequest& request) 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;
const DOMElement* getElement() const;
private:
- IRequestMapper* m_mapper;
+ RequestMapper* m_mapper;
ThreadKey* m_stKey;
ThreadKey* m_propsKey;
};
-IPlugIn* SunRequestMapFactory(const DOMElement* e)
+RequestMapper* SunRequestMapFactory(const DOMElement* const & e)
{
return new SunRequestMapper(e);
}
SunRequestMapper::SunRequestMapper(const DOMElement* e) : m_mapper(NULL), m_stKey(NULL), m_propsKey(NULL)
{
- IPlugIn* p=SAMLConfig::getConfig().getPlugMgr().newPlugin(XML_REQUESTMAP_PROVIDER,e);
- m_mapper=dynamic_cast<IRequestMapper*>(p);
- if (!m_mapper) {
- delete p;
- throw UnsupportedExtensionException("Embedded request mapper plugin was not of correct type.");
- }
+ m_mapper = SPConfig::getConfig().RequestMapperManager.newPlugin(XML_REQUEST_MAPPER,e);
m_stKey=ThreadKey::create(NULL);
m_propsKey=ThreadKey::create(NULL);
}
-IRequestMapper::Settings SunRequestMapper::getSettings(ShibTarget* st) const
+RequestMapper::Settings SunRequestMapper::getSettings(const SPRequest& request) const
{
- Settings s=m_mapper->getSettings(st);
- m_stKey->setData(dynamic_cast<ShibTargetNSAPI*>(st));
+ Settings s=m_mapper->getSettings(request);
+ m_stKey->setData((void*)dynamic_cast<const ShibTargetNSAPI*>(&request));
m_propsKey->setData((void*)s.first);
- return pair<const PropertySet*,IAccessControl*>(this,s.second);
+ return pair<const PropertySet*,AccessControl*>(this,s.second);
}
pair<bool,bool> SunRequestMapper::getBool(const char* name, const char* ns) const
{
- ShibTargetNSAPI* stn=reinterpret_cast<ShibTargetNSAPI*>(m_stKey->getData());
+ const ShibTargetNSAPI* stn=reinterpret_cast<const ShibTargetNSAPI*>(m_stKey->getData());
const PropertySet* s=reinterpret_cast<const PropertySet*>(m_propsKey->getData());
if (stn && !ns && name) {
// Override boolean properties.
pair<bool,const char*> SunRequestMapper::getString(const char* name, const char* ns) const
{
- ShibTargetNSAPI* stn=reinterpret_cast<ShibTargetNSAPI*>(m_stKey->getData());
+ const ShibTargetNSAPI* stn=reinterpret_cast<const ShibTargetNSAPI*>(m_stKey->getData());
const PropertySet* s=reinterpret_cast<const PropertySet*>(m_propsKey->getData());
if (stn && !ns && name) {
// Override string properties.
pair<bool,unsigned int> SunRequestMapper::getUnsignedInt(const char* name, const char* ns) const
{
- ShibTargetNSAPI* stn=reinterpret_cast<ShibTargetNSAPI*>(m_stKey->getData());
+ const ShibTargetNSAPI* stn=reinterpret_cast<const ShibTargetNSAPI*>(m_stKey->getData());
const PropertySet* s=reinterpret_cast<const PropertySet*>(m_propsKey->getData());
if (stn && !ns && name) {
// Override int properties.
pair<bool,int> SunRequestMapper::getInt(const char* name, const char* ns) const
{
- ShibTargetNSAPI* stn=reinterpret_cast<ShibTargetNSAPI*>(m_stKey->getData());
+ const ShibTargetNSAPI* stn=reinterpret_cast<const ShibTargetNSAPI*>(m_stKey->getData());
const PropertySet* s=reinterpret_cast<const PropertySet*>(m_propsKey->getData());
if (stn && !ns && name) {
// Override int properties.
SPConfig::Credentials |
SPConfig::AAP |
SPConfig::OutOfProcess |
- (shar_checkonly ? (SPConfig::InProcess | SPConfig::RequestMapper) : SPConfig::Logging)
+ (shar_checkonly ? (SPConfig::InProcess | SPConfig::RequestMapping) : SPConfig::Logging)
);
if (!shar_config)
shar_config=getenv("SHIBCONFIG");
SPConfig::Credentials |
SPConfig::AAP |
SPConfig::OutOfProcess |
- (shar_checkonly ? (SPConfig::InProcess | SPConfig::RequestMapper) : SPConfig::Logging)
+ (shar_checkonly ? (SPConfig::InProcess | SPConfig::RequestMapping) : SPConfig::Logging)
);
if (!conf.init(shar_schemadir) || !conf.load(shar_config)) {
fprintf(stderr, "configuration is invalid, check console for specific problems\n");
shib-config.cpp \
shib-handlers.cpp \
shib-ini.cpp \
- shib-target.cpp \
- XMLRequestMapper.cpp
+ shib-target.cpp
# this is different from the project version
# http://sources.redhat.com/autobook/autobook/autobook_91.html
# include "config.h"
#endif
-#include <shibsp/SPConstants.h>
+#include <shibsp/util/SPConstants.h>
#include "shib-target.h"
#include "hresult.h"
// Find application.
xmltooling::Locker confLocker(ShibTargetConfig::getConfig().getINI());
const char* aid=in["application_id"].string();
- const IApplication* app=aid ? ShibTargetConfig::getConfig().getINI()->getApplication(aid) : NULL;
+ const IApplication* app=aid ? dynamic_cast<const IApplication*>(ShibTargetConfig::getConfig().getINI()->getApplication(aid)) : NULL;
if (!app) {
// Something's horribly wrong.
m_log->error("couldn't find application (%s) for session", aid ? aid : "(missing)");
m_log->error("cache store returned failure during search");
return NULL;
}
- const IApplication* eapp=ShibTargetConfig::getConfig().getINI()->getApplication(appid.c_str());
+ const IApplication* eapp=dynamic_cast<const IApplication*>(ShibTargetConfig::getConfig().getINI()->getApplication(appid.c_str()));
if (!eapp) {
// Something's horribly wrong.
m_log->error("couldn't find application (%s) for session", appid.c_str());
#include "internal.h"
#include <shibsp/SPConfig.h>
-#include <shibsp/SPConstants.h>
#include <xmltooling/XMLToolingConfig.h>
#include <log4cpp/OstreamAppender.hh>
PlugManager::Factory TCPListenerFactory;
//PlugManager::Factory MemoryListenerFactory;
PlugManager::Factory MemoryCacheFactory;
-PlugManager::Factory XMLRequestMapFactory;
PlugManager::Factory ShibSessionInitiatorFactory;
PlugManager::Factory SAML1POSTFactory;
PlugManager::Factory SAML1ArtifactFactory;
SPConfig::getConfig().ServiceProviderManager.registerFactory(XML_SERVICE_PROVIDER, XMLServiceProviderFactory);
samlConf.getPlugMgr().regFactory(MEMORY_SESSIONCACHE,&MemoryCacheFactory);
- samlConf.getPlugMgr().regFactory(LEGACY_REQUESTMAP_PROVIDER,&XMLRequestMapFactory);
- samlConf.getPlugMgr().regFactory(XML_REQUESTMAP_PROVIDER,&XMLRequestMapFactory);
- samlConf.getPlugMgr().regFactory(NATIVE_REQUESTMAP_PROVIDER,&XMLRequestMapFactory);
auto_ptr_char temp1(shibspconstants::SHIB1_SESSIONINIT_PROFILE_URI);
samlConf.getPlugMgr().regFactory(temp1.get(),&ShibSessionInitiatorFactory);
#include <saml/saml2/metadata/EndpointManager.h>
#include <saml/util/CommonDomainCookie.h>
#include <shibsp/SPConfig.h>
-#include <shibsp/SPConstants.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
public:
SessionInitiator(const DOMElement* e) {}
~SessionInitiator() {}
- pair<bool,void*> run(ShibTarget* st, bool isHandler=true) const;
- pair<bool,void*> ShibAuthnRequest(
+ pair<bool,long> run(ShibTarget* st, bool isHandler=true) const;
+ pair<bool,long> ShibAuthnRequest(
ShibTarget* st,
const IHandler* shire,
const char* dest,
public:
SAML1Consumer(const DOMElement* e);
~SAML1Consumer();
- pair<bool,void*> run(ShibTarget* st, bool isHandler=true) const;
+ pair<bool,long> run(ShibTarget* st, bool isHandler=true) const;
DDF receive(const DDF& in);
private:
string m_address;
public:
ShibLogout(const DOMElement* e) {}
~ShibLogout() {}
- pair<bool,void*> run(ShibTarget* st, bool isHandler=true) const;
+ pair<bool,long> run(ShibTarget* st, bool isHandler=true) const;
};
}
return new ShibLogout(e);
}
-pair<bool,void*> SessionInitiator::run(ShibTarget* st, bool isHandler) const
+pair<bool,long> SessionInitiator::run(ShibTarget* st, bool isHandler) const
{
string dupresource;
const char* resource=NULL;
* acsIndex optional index of an ACS to use on the way back in
* providerId optional direct invocation of a specific IdP
*/
- const char* option=st->getRequestParameter("acsIndex");
+ const char* option=st->getParameter("acsIndex");
if (option)
ACS=app->getAssertionConsumerServiceByIndex(atoi(option));
- option=st->getRequestParameter("providerId");
+ option=st->getParameter("providerId");
- resource=st->getRequestParameter("target");
+ resource=st->getParameter("target");
if (!resource || !*resource) {
pair<bool,const char*> home=app->getString("homeURL");
if (home.first)
throw ConfigurationException("E-Authn requests cannot include relay state, so localRelayState must be enabled.");
// Here we store the state in a cookie.
- pair<string,const char*> shib_cookie=st->getCookieNameProps("_shibstate_");
- st->setCookie(shib_cookie.first,opensaml::SAMLConfig::getConfig().getURLEncoder()->encode(resource) + shib_cookie.second);
+ pair<string,const char*> shib_cookie=app->getCookieNameProps("_shibstate_");
+ string stateval = opensaml::SAMLConfig::getConfig().getURLEncoder()->encode(resource) + shib_cookie.second;
+ st->setCookie(shib_cookie.first.c_str(),stateval.c_str());
return make_pair(true, st->sendRedirect(wayfURL.second));
}
}
// Handles Shib 1.x AuthnRequest profile.
-pair<bool,void*> SessionInitiator::ShibAuthnRequest(
+pair<bool,long> SessionInitiator::ShibAuthnRequest(
ShibTarget* st,
const IHandler* shire,
const char* dest,
else {
// Here we store the state in a cookie and send a fixed
// value to the IdP so we can recognize it on the way back.
- pair<string,const char*> shib_cookie=st->getCookieNameProps("_shibstate_");
- st->setCookie(shib_cookie.first,urlenc->encode(target) + shib_cookie.second);
+ pair<string,const char*> shib_cookie=st->getApplication()->getCookieNameProps("_shibstate_");
+ string stateval = urlenc->encode(target) + shib_cookie.second;
+ st->setCookie(shib_cookie.first.c_str(),stateval.c_str());
req+="&target=cookie";
}
if (providerId)
req+="&providerId=" + urlenc->encode(providerId);
- return make_pair(true, st->sendRedirect(req));
+ return make_pair(true, st->sendRedirect(req.c_str()));
}
SAML1Consumer::SAML1Consumer(const DOMElement* e)
// Find application.
const char* aid=in["application_id"].string();
- const IApplication* app=aid ? ShibTargetConfig::getConfig().getINI()->getApplication(aid) : NULL;
+ const IApplication* app=aid ? dynamic_cast<const IApplication*>(ShibTargetConfig::getConfig().getINI()->getApplication(aid)) : NULL;
if (!app) {
// Something's horribly wrong.
log.error("couldn't find application (%s) for new session", aid ? aid : "(missing)");
return out;
}
-pair<bool,void*> SAML1Consumer::run(ShibTarget* st, bool isHandler) const
+pair<bool,long> SAML1Consumer::run(ShibTarget* st, bool isHandler) const
{
DDF in,out;
DDFJanitor jin(in),jout(out);
pair<bool,const XMLCh*> binding=getProperties()->getXMLString("Binding");
if (!binding.first || !XMLString::compareString(binding.second,SAMLBrowserProfile::BROWSER_POST)) {
#ifdef HAVE_STRCASECMP
- if (strcasecmp(st->getRequestMethod(), "POST")) {
+ if (strcasecmp(st->getMethod(), "POST")) {
#else
- if (_stricmp(st->getRequestMethod(), "POST")) {
+ if (_stricmp(st->getMethod(), "POST")) {
#endif
- st->log(ShibTarget::LogLevelInfo, "SAML 1.x Browser/POST handler ignoring non-POST request");
- return pair<bool,void*>(false,NULL);
+ st->log(SPRequest::SPInfo, "SAML 1.x Browser/POST handler ignoring non-POST request");
+ return pair<bool,long>(false,NULL);
}
#ifdef HAVE_STRCASECMP
- if (!st->getContentType() || strcasecmp(st->getContentType(),"application/x-www-form-urlencoded")) {
+ if (strcasecmp(st->getContentType().c_str(),"application/x-www-form-urlencoded")) {
#else
- if (!st->getContentType() || _stricmp(st->getContentType(),"application/x-www-form-urlencoded")) {
+ if (_stricmp(st->getContentType().c_str(),"application/x-www-form-urlencoded")) {
#endif
- st->log(ShibTarget::LogLevelInfo, "SAML 1.x Browser/POST handler ignoring submission with unknown content-type.");
- return pair<bool,void*>(false,NULL);
+ st->log(SPRequest::SPInfo, "SAML 1.x Browser/POST handler ignoring submission with unknown content-type.");
+ return pair<bool,long>(false,0);
}
- const char* samlResponse = st->getRequestParameter("SAMLResponse");
+ const char* samlResponse = st->getParameter("SAMLResponse");
if (!samlResponse) {
- st->log(ShibTarget::LogLevelInfo, "SAML 1.x Browser/POST handler ignoring request with no SAMLResponse parameter.");
- return pair<bool,void*>(false,NULL);
+ st->log(SPRequest::SPInfo, "SAML 1.x Browser/POST handler ignoring request with no SAMLResponse parameter.");
+ return pair<bool,long>(false,0);
}
in=DDF(m_address.c_str()).structure();
}
else if (!XMLString::compareString(binding.second,SAMLBrowserProfile::BROWSER_ARTIFACT)) {
#ifdef HAVE_STRCASECMP
- if (strcasecmp(st->getRequestMethod(), "GET")) {
+ if (strcasecmp(st->getMethod(), "GET")) {
#else
- if (_stricmp(st->getRequestMethod(), "GET")) {
+ if (_stricmp(st->getMethod(), "GET")) {
#endif
- st->log(ShibTarget::LogLevelInfo, "SAML 1.x Browser/Artifact handler ignoring non-GET request");
- return pair<bool,void*>(false,NULL);
+ st->log(SPRequest::SPInfo, "SAML 1.x Browser/Artifact handler ignoring non-GET request");
+ return pair<bool,long>(false,0);
}
- const char* SAMLart=st->getRequestParameter("SAMLart");
- if (!SAMLart) {
- st->log(ShibTarget::LogLevelInfo, "SAML 1.x Browser/Artifact handler ignoring request with no SAMLart parameter.");
- return pair<bool,void*>(false,NULL);
+ vector<const char*> arts;
+ if (st->getParameters("SAMLart",arts)==0) {
+ st->log(SPRequest::SPInfo, "SAML 1.x Browser/Artifact handler ignoring request with no SAMLart parameter.");
+ return pair<bool,long>(false,0);
}
in=DDF(m_address.c_str()).structure();
DDF artlist=in.addmember("SAMLart").list();
- while (SAMLart) {
- artlist.add(DDF(NULL).string(SAMLart));
- SAMLart=st->getRequestParameter("SAMLart",artlist.integer());
- }
+ for (vector<const char*>::const_iterator a=arts.begin(); a!=arts.end(); ++a)
+ artlist.add(DDF(NULL).string(*a));
}
// Compute the endpoint location.
// Add remaining parameters.
in.addmember("application_id").string(st->getApplication()->getId());
- in.addmember("client_address").string(st->getRemoteAddr());
+ in.addmember("client_address").string(st->getRemoteAddr().c_str());
out=st->getConfig()->getListenerService()->send(in);
if (!out["key"].isstring())
throw opensaml::FatalProfileException("Remote processing of SAML 1.x Browser profile did not return a usable session key.");
string key=out["key"].string();
- st->log(ShibTarget::LogLevelDebug, string("profile processing succeeded, new session created (") + key + ")");
+ st->log(SPRequest::SPDebug, string("profile processing succeeded, new session created (") + key + ")");
- const char* target=st->getRequestParameter("TARGET");
+ const char* target=st->getParameter("TARGET");
if (target && !strcmp(target,"default")) {
pair<bool,const char*> homeURL=st->getApplication()->getString("homeURL");
target=homeURL.first ? homeURL.second : "/";
}
else if (!target || !strcmp(target,"cookie")) {
// Pull the target value from the "relay state" cookie.
- pair<string,const char*> relay_cookie = st->getCookieNameProps("_shibstate_");
- const char* relay_state = st->getCookie(relay_cookie.first);
+ pair<string,const char*> relay_cookie = st->getApplication()->getCookieNameProps("_shibstate_");
+ const char* relay_state = st->getCookie(relay_cookie.first.c_str());
if (!relay_state || !*relay_state) {
// No apparent relay state value to use, so fall back on the default.
pair<bool,const char*> homeURL=st->getApplication()->getString("homeURL");
free(rscopy);
target=hURL.c_str();
}
- st->setCookie(relay_cookie.first,relay_cookie.second);
+ st->setCookie(relay_cookie.first.c_str(),relay_cookie.second);
}
// We've got a good session, set the session cookie.
- pair<string,const char*> shib_cookie=st->getCookieNameProps("_shibsession_");
- st->setCookie(shib_cookie.first, key + shib_cookie.second);
+ pair<string,const char*> shib_cookie=st->getApplication()->getCookieNameProps("_shibsession_");
+ key += shib_cookie.second;
+ st->setCookie(shib_cookie.first.c_str(), key.c_str());
const char* providerId=out["provider_id"].string();
if (providerId) {
// Either leave in memory or set an expiration.
pair<bool,unsigned int> days=sessionProps->getUnsignedInt("idpHistoryDays");
- if (!days.first || days.second==0)
- st->setCookie(CommonDomainCookie::CDCName,string(cdc.set(providerId)) + shib_cookie.second);
- else {
- time_t now=time(NULL) + (days.second * 24 * 60 * 60);
+ if (!days.first || days.second==0) {
+ key = string(cdc.set(providerId)) + shib_cookie.second;
+ st->setCookie(CommonDomainCookie::CDCName, key.c_str());
+ }
+ else {
+ time_t now=time(NULL) + (days.second * 24 * 60 * 60);
#ifdef HAVE_GMTIME_R
- struct tm res;
- struct tm* ptime=gmtime_r(&now,&res);
+ struct tm res;
+ struct tm* ptime=gmtime_r(&now,&res);
#else
- struct tm* ptime=gmtime(&now);
+ struct tm* ptime=gmtime(&now);
#endif
- char timebuf[64];
- strftime(timebuf,64,"%a, %d %b %Y %H:%M:%S GMT",ptime);
- st->setCookie(
- CommonDomainCookie::CDCName,
- string(cdc.set(providerId)) + shib_cookie.second + "; expires=" + timebuf
- );
+ char timebuf[64];
+ strftime(timebuf,64,"%a, %d %b %Y %H:%M:%S GMT",ptime);
+ key = string(cdc.set(providerId)) + shib_cookie.second + "; expires=" + timebuf;
+ st->setCookie(CommonDomainCookie::CDCName, key.c_str());
}
}
}
return make_pair(true, st->sendRedirect(target));
}
-pair<bool,void*> ShibLogout::run(ShibTarget* st, bool isHandler) const
+pair<bool,long> ShibLogout::run(ShibTarget* st, bool isHandler) const
{
// Recover the session key.
- pair<string,const char*> shib_cookie = st->getCookieNameProps("_shibsession_");
- const char* session_id = st->getCookie(shib_cookie.first);
+ pair<string,const char*> shib_cookie = st->getApplication()->getCookieNameProps("_shibsession_");
+ const char* session_id = st->getCookie(shib_cookie.first.c_str());
// Logout is best effort.
if (session_id && *session_id) {
try {
- st->getConfig()->getSessionCache()->remove(session_id,st->getApplication(),st->getRemoteAddr());
+ st->getConfig()->getSessionCache()->remove(session_id,st->getApplication(),st->getRemoteAddr().c_str());
}
catch (exception& e) {
- st->log(ShibTarget::LogLevelError, string("logout processing failed with exception: ") + e.what());
+ st->log(SPRequest::SPError, string("logout processing failed with exception: ") + e.what());
}
#ifndef _DEBUG
catch (...) {
- st->log(ShibTarget::LogLevelError, "logout processing failed with unknown exception");
+ st->log(SPRequest::SPError, "logout processing failed with unknown exception");
}
#endif
// We send the cookie property alone, which acts as an empty value.
- st->setCookie(shib_cookie.first,shib_cookie.second);
+ st->setCookie(shib_cookie.first.c_str(),shib_cookie.second);
}
- const char* ret=st->getRequestParameter("return");
+ const char* ret=st->getParameter("return");
if (!ret)
ret=getProperties()->getString("ResponseLocation").second;
if (!ret)
#include <sys/stat.h>
#include <log4cpp/Category.hh>
#include <log4cpp/PropertyConfigurator.hh>
-#include <shibsp/DOMPropertySet.h>
-#include <shibsp/PKIXTrustEngine.h>
+#include <shibsp/RequestMapper.h>
#include <shibsp/SPConfig.h>
-#include <shibsp/SPConstants.h>
+#include <shibsp/security/PKIXTrustEngine.h>
+#include <shibsp/util/DOMPropertySet.h>
#include <saml/SAMLConfig.h>
#include <saml/saml1/core/Assertions.h>
#include <saml/saml2/metadata/ChainingMetadataProvider.h>
XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* outer);
~XMLConfigImpl();
- IRequestMapper* m_requestMapper;
+ RequestMapper* m_requestMapper;
map<string,IApplication*> m_appmap;
map<string,CredentialResolver*> m_credResolverMap;
vector<IAttributeFactory*> m_attrFactories;
ISessionCache* getSessionCache() const {return m_sessionCache;}
IReplayCache* getReplayCache() const {return m_replayCache;}
- IRequestMapper* getRequestMapper() const {return m_impl->m_requestMapper;}
+ RequestMapper* getRequestMapper() const {return m_impl->m_requestMapper;}
const IApplication* getApplication(const char* applicationId) const {
map<string,IApplication*>::const_iterator i=m_impl->m_appmap.find(applicationId);
return (i!=m_impl->m_appmap.end()) ? i->second : NULL;
#endif
static const XMLCh AAPProvider[] = UNICODE_LITERAL_11(A,A,P,P,r,o,v,i,d,e,r);
- static const XMLCh Application[] = UNICODE_LITERAL_11(A,p,p,l,i,c,a,t,i,o,n);
+ static const XMLCh _Application[] = UNICODE_LITERAL_11(A,p,p,l,i,c,a,t,i,o,n);
static const XMLCh Applications[] = UNICODE_LITERAL_12(A,p,p,l,i,c,a,t,i,o,n,s);
static const XMLCh AttributeFactory[] = UNICODE_LITERAL_16(A,t,t,r,i,b,u,t,e,F,a,c,t,o,r,y);
static const XMLCh Credentials[] = UNICODE_LITERAL_11(C,r,e,d,e,n,t,i,a,l,s);
else if (XMLHelper::isNodeNamed(node,samlconstants::SAML1_NS,Audience::LOCAL_NAME))
return FILTER_REJECT;
const XMLCh* name=node->getLocalName();
- if (XMLString::equals(name,Application) ||
+ if (XMLString::equals(name,_Application) ||
XMLString::equals(name,AssertionConsumerService::LOCAL_NAME) ||
XMLString::equals(name,SingleLogoutService::LOCAL_NAME) ||
XMLString::equals(name,DiagnosticService) ||
} // end of first-time-only stuff
// Back to the fully dynamic stuff...next up is the RequestMapper.
- if (conf.isEnabled(SPConfig::RequestMapper)) {
+ if (conf.isEnabled(SPConfig::RequestMapping)) {
child=XMLHelper::getFirstChildElement(SHIRE,RequestMapProvider);
if (child) {
xmltooling::auto_ptr_char type(child->getAttributeNS(NULL,_type));
log.info("building RequestMapper of type %s...",type.get());
- plugin=shibConf.getPlugMgr().newPlugin(type.get(),child);
- if (plugin) {
- IRequestMapper* reqmap=dynamic_cast<IRequestMapper*>(plugin);
- if (reqmap)
- m_requestMapper=reqmap;
- else {
- delete plugin;
- log.fatal("plugin was not a RequestMapper object");
- throw UnknownExtensionException("plugin was not a RequestMapper object");
- }
- }
+ m_requestMapper=conf.RequestMapperManager.newPlugin(type.get(),child);
}
else {
log.fatal("can't build RequestMapper, missing conf:RequestMapProvider element?");
m_appmap[defapp->getId()]=defapp;
// Load any overrides.
- child = XMLHelper::getFirstChildElement(child,Application);
+ child = XMLHelper::getFirstChildElement(child,_Application);
while (child) {
auto_ptr<XMLApplication> iapp(new XMLApplication(m_outer,child,defapp));
if (m_appmap.find(iapp->getId())!=m_appmap.end())
else
m_appmap[iapp->getId()]=iapp.release();
- child = XMLHelper::getNextSiblingElement(child,Application);
+ child = XMLHelper::getNextSiblingElement(child,_Application);
}
}
catch (exception&) {
# include <unistd.h>
#endif
-#include <ctime>
-#include <sstream>
#include <fstream>
-#include <stdexcept>
#include <saml/SAMLConfig.h>
-#include <saml/binding/URLEncoder.h>
#include <xercesc/util/Base64.hpp>
+#include <shibsp/AccessControl.h>
+#include <shibsp/RequestMapper.h>
#include <xmltooling/util/NDC.h>
#include <xmltooling/util/TemplateEngine.h>
#include <xmltooling/util/XMLHelper.h>
using xmltooling::XMLHelper;
namespace shibtarget {
- class CgiParse
- {
- public:
- CgiParse(const ShibTarget* st);
- ~CgiParse();
-
- typedef multimap<string,char*>::const_iterator walker;
- pair<walker,walker> get_values(const char* name) const;
-
- private:
- char* fmakeword(char stop, unsigned int *cl, const char** ppch);
- char* makeword(char *line, char stop);
- void plustospace(char *str);
-
- multimap<string,char*> kvp_map;
- };
class ExtTemplateParameters : public TemplateEngine::TemplateParameters
{
// Helper functions
void get_application(ShibTarget* st, const string& protocol, const string& hostname, int port, const string& uri);
- void* sendError(ShibTarget* st, const char* page, ExtTemplateParameters& tp, const XMLToolingException* ex=NULL);
+ long sendError(ShibTarget* st, const char* page, ExtTemplateParameters& tp, const XMLToolingException* ex=NULL);
void clearHeaders(ShibTarget* st);
private:
friend class ShibTarget;
- IRequestMapper::Settings m_settings;
+ RequestMapper::Settings m_settings;
const IApplication *m_app;
- mutable string m_handlerURL;
- mutable map<string,string> m_cookieMap;
- mutable CgiParse* m_cgiParser;
ISessionCacheEntry* m_cacheEntry;
ShibTargetConfig* m_Config;
IConfig* m_conf;
- IRequestMapper* m_mapper;
+ RequestMapper* m_mapper;
};
static const XMLCh SessionInitiator[] = UNICODE_LITERAL_16(S,e,s,s,i,o,n,I,n,i,t,i,a,t,o,r);
}
void ShibTarget::init(
- const char* protocol,
+ const char* scheme,
const char* hostname,
int port,
const char* uri,
throw XMLToolingException("Request initialization occurred twice!");
if (method) m_method = method;
- if (protocol) m_protocol = protocol;
+ if (scheme) m_scheme = scheme;
if (hostname) m_hostname = hostname;
if (uri) m_uri = uri;
if (content_type) m_content_type = content_type;
if (remote_addr) m_remote_addr = remote_addr;
m_port = port;
m_priv->m_Config = &ShibTargetConfig::getConfig();
- m_priv->get_application(this, protocol, hostname, port, uri);
+ m_priv->get_application(this, scheme, hostname, port, uri);
+ AbstractSPRequest::m_app = m_priv->m_app;
}
// The web server modules implement a subclass and then call into
// these methods once they instantiate their request object.
-pair<bool,void*> ShibTarget::doCheckAuthN(bool handler)
+pair<bool,long> ShibTarget::doCheckAuthN(bool handler)
{
#ifdef _DEBUG
xmltooling::NDC ndc("doCheckAuthN");
throw ConfigurationException("System uninitialized, application did not supply request information.");
// If not SSL, check to see if we should block or redirect it.
- if (!strcmp("http",getProtocol())) {
+ if (!strcmp("http",getScheme())) {
pair<bool,const char*> redirectToSSL = m_priv->m_settings.first->getString("redirectToSSL");
if (redirectToSSL.first) {
- if (!strcasecmp("GET",getRequestMethod()) || !strcasecmp("HEAD",getRequestMethod())) {
+ if (!strcasecmp("GET",getMethod()) || !strcasecmp("HEAD",getMethod())) {
// Compute the new target URL
string redirectURL = string("https://") + getHostname();
if (strcmp(redirectToSSL.second,"443")) {
redirectURL = redirectURL + ':' + redirectToSSL.second;
}
redirectURL += getRequestURI();
- return make_pair(true, sendRedirect(redirectURL));
+ return make_pair(true, sendRedirect(redirectURL.c_str()));
}
else {
tp.m_map["requestURL"] = m_url.substr(0,m_url.find('?'));
// Fix for secadv 20050901
m_priv->clearHeaders(this);
- pair<string,const char*> shib_cookie = getCookieNameProps("_shibsession_");
- const char* session_id = getCookie(shib_cookie.first);
+ pair<string,const char*> shib_cookie = m_priv->m_app->getCookieNameProps("_shibsession_");
+ const char* session_id = getCookie(shib_cookie.first.c_str());
if (!session_id || !*session_id) {
// No session. Maybe that's acceptable?
if ((!requireSession.first || !requireSession.second) && !requireSessionWith.first)
throw RetryableProfileException("Session no longer valid.");
}
catch (exception& e) {
- log(LogLevelError, string("session processing failed: ") + e.what());
+ log(SPError, string("session processing failed: ") + e.what());
// If no session is required, bail now.
if ((!requireSession.first || !requireSession.second) && !requireSessionWith.first)
// We're done. Everything is okay. Nothing to report. Nothing to do..
// Let the caller decide how to proceed.
- log(LogLevelDebug, "doCheckAuthN succeeded");
- return make_pair(false,(void*)NULL);
+ log(SPDebug, "doCheckAuthN succeeded");
+ return make_pair(false,0);
}
catch (XMLToolingException& e) {
tp.m_map["errorType"] = procState;
#endif
}
-pair<bool,void*> ShibTarget::doHandler(void)
+pair<bool,long> ShibTarget::doHandler(void)
{
#ifdef _DEBUG
xmltooling::NDC ndc("doHandler");
pair<bool,bool> handlerSSL=sessionProps->getBool("handlerSSL");
// Make sure this is SSL, if it should be
- if ((!handlerSSL.first || handlerSSL.second) && m_protocol != "https")
- throw opensaml::FatalProfileException("Blocked non-SSL access to Shibboleth handler.");
+ if ((!handlerSSL.first || handlerSSL.second) && m_scheme != "https")
+ throw FatalProfileException("Blocked non-SSL access to Shibboleth handler.");
// We dispatch based on our path info. We know the request URL begins with or equals the handler URL,
// so the path info is the next character (or null).
procState = "Diagnostics Error";
else
procState = "Extension Service Error";
- pair<bool,void*> hret=handler->run(this);
+ pair<bool,long> hret=handler->run(this);
// Did the handler run successfully?
if (hret.first)
#endif
}
-pair<bool,void*> ShibTarget::doCheckAuthZ(void)
+pair<bool,long> ShibTarget::doCheckAuthZ(void)
{
#ifdef _DEBUG
xmltooling::NDC ndc("doCheckAuthZ");
if (!m_priv->m_cacheEntry) {
// No data yet, so we may need to try and get the session.
- pair<string,const char*> shib_cookie=getCookieNameProps("_shibsession_");
- const char *session_id = getCookie(shib_cookie.first);
+ pair<string,const char*> shib_cookie=m_priv->m_app->getCookieNameProps("_shibsession_");
+ const char *session_id = getCookie(shib_cookie.first.c_str());
try {
if (session_id && *session_id) {
m_priv->m_cacheEntry=m_priv->m_conf->getSessionCache()->find(
}
}
catch (exception&) {
- log(LogLevelError, "doCheckAuthZ: unable to obtain session information to pass to access control provider");
+ log(SPError, "doCheckAuthZ: unable to obtain session information to pass to access control provider");
}
}
xmltooling::Locker acllock(m_priv->m_settings.second);
+ /* TODO: port
if (m_priv->m_settings.second->authorized(this,m_priv->m_cacheEntry)) {
// Let the caller decide how to proceed.
log(LogLevelDebug, "doCheckAuthZ: access control provider granted access");
- return make_pair(false,(void*)NULL);
+ return make_pair(false,0);
}
else {
log(LogLevelWarn, "doCheckAuthZ: access control provider denied access");
tp.m_map["requestURL"] = targetURL;
return make_pair(true,m_priv->sendError(this, "access", tp));
}
+ */
+ return make_pair(false,0);
}
else
return make_pair(true,returnDecline());
#endif
}
-pair<bool,void*> ShibTarget::doExportAssertions(bool requireSession)
+pair<bool,long> ShibTarget::doExportAssertions(bool requireSession)
{
#ifdef _DEBUG
xmltooling::NDC ndc("doExportAssertions");
if (!m_priv->m_cacheEntry) {
// No data yet, so we need to get the session. This can only happen
// if the call to doCheckAuthn doesn't happen in the same object lifetime.
- pair<string,const char*> shib_cookie=getCookieNameProps("_shibsession_");
- const char *session_id = getCookie(shib_cookie.first);
+ pair<string,const char*> shib_cookie=m_priv->m_app->getCookieNameProps("_shibsession_");
+ const char *session_id = getCookie(shib_cookie.first.c_str());
try {
if (session_id && *session_id) {
m_priv->m_cacheEntry=m_priv->m_conf->getSessionCache()->find(
}
}
catch (exception&) {
- log(LogLevelError, "unable to obtain session information to export into request headers");
+ log(SPError, "unable to obtain session information to export into request headers");
// If we have to have a session, then this is a fatal error.
if (requireSession)
throw;
if (requireSession)
throw RetryableProfileException("Unable to obtain session information for request.");
else
- return make_pair(false,(void*)NULL); // just bail silently
+ return make_pair(false,0); // just bail silently
}
// Extract data from session.
Iterator<string> vals=attr->getSingleByteValues();
if (!strcmp(rule->getHeader(),"REMOTE_USER") && vals.hasNext())
- setRemoteUser(vals.next());
+ setRemoteUser(vals.next().c_str());
else {
int it=0;
- string header = getHeader(rule->getHeader());
+ string header = getSecureHeader(rule->getHeader());
if (!header.empty())
it++;
for (; vals.hasNext(); it++) {
header += ";";
header += value;
}
- setHeader(rule->getHeader(), header);
+ setHeader(rule->getHeader(), header.c_str());
}
}
}
}
}
- return make_pair(false,(void*)NULL);
+ return make_pair(false,0);
}
catch (XMLToolingException& e) {
tp.m_map["errorType"] = procState;
#endif
}
-const char* ShibTarget::getRequestParameter(const char* param, size_t index) const
-{
- if (!m_priv->m_cgiParser)
- m_priv->m_cgiParser=new CgiParse(this);
-
- pair<CgiParse::walker,CgiParse::walker> bounds=m_priv->m_cgiParser->get_values(param);
-
- // Advance to the right index.
- while (index && bounds.first!=bounds.second) {
- index--;
- bounds.first++;
- }
-
- return (bounds.first==bounds.second) ? NULL : bounds.first->second;
-}
-
-const char* ShibTarget::getCookie(const string& name) const
-{
- if (m_priv->m_cookieMap.empty()) {
- string cookies=getCookies();
-
- string::size_type pos=0,cname,namelen,val,vallen;
- while (pos !=string::npos && pos < cookies.length()) {
- while (isspace(cookies[pos])) pos++;
- cname=pos;
- pos=cookies.find_first_of("=",pos);
- if (pos == string::npos)
- break;
- namelen=pos-cname;
- pos++;
- if (pos==cookies.length())
- break;
- val=pos;
- pos=cookies.find_first_of(";",pos);
- if (pos != string::npos) {
- vallen=pos-val;
- pos++;
- m_priv->m_cookieMap.insert(make_pair(cookies.substr(cname,namelen),cookies.substr(val,vallen)));
- }
- else
- m_priv->m_cookieMap.insert(make_pair(cookies.substr(cname,namelen),cookies.substr(val)));
- }
- }
- map<string,string>::const_iterator lookup=m_priv->m_cookieMap.find(name);
- return (lookup==m_priv->m_cookieMap.end()) ? NULL : lookup->second.c_str();
-}
-
-pair<string,const char*> ShibTarget::getCookieNameProps(const char* prefix) const
-{
- static const char* defProps="; path=/";
-
- const PropertySet* props=m_priv->m_app ? m_priv->m_app->getPropertySet("Sessions") : NULL;
- if (props) {
- pair<bool,const char*> p=props->getString("cookieProps");
- if (!p.first)
- p.second=defProps;
- pair<bool,const char*> p2=props->getString("cookieName");
- if (p2.first)
- return make_pair(string(prefix) + p2.second,p.second);
- return make_pair(string(prefix) + m_priv->m_app->getHash(),p.second);
- }
-
- // Shouldn't happen, but just in case..
- return pair<string,const char*>(prefix,defProps);
-}
-
-string ShibTarget::getHandlerURL(const char* resource) const
-{
- if (!m_priv->m_handlerURL.empty() && resource && !strcmp(getRequestURL(),resource))
- return m_priv->m_handlerURL;
-
- if (!m_priv->m_app)
- throw ConfigurationException("Internal error in ShibTargetPriv::getHandlerURL, missing application pointer.");
-
- bool ssl_only=false;
- const char* handler=NULL;
- const PropertySet* props=m_priv->m_app->getPropertySet("Sessions");
- if (props) {
- pair<bool,bool> p=props->getBool("handlerSSL");
- if (p.first)
- ssl_only=p.second;
- pair<bool,const char*> p2=props->getString("handlerURL");
- if (p2.first)
- handler=p2.second;
- }
-
- // Should never happen...
- if (!handler || (*handler!='/' && strncmp(handler,"http:",5) && strncmp(handler,"https:",6)))
- throw ConfigurationException(
- "Invalid handlerURL property ($1) in Application ($2)",
- xmltooling::params(2, handler ? handler : "null", m_priv->m_app->getId())
- );
-
- // The "handlerURL" property can be in one of three formats:
- //
- // 1) a full URI: http://host/foo/bar
- // 2) a hostless URI: http:///foo/bar
- // 3) a relative path: /foo/bar
- //
- // # Protocol Host Path
- // 1 handler handler handler
- // 2 handler resource handler
- // 3 resource resource handler
- //
- // note: if ssl_only is true, make sure the protocol is https
-
- const char* path = NULL;
-
- // Decide whether to use the handler or the resource for the "protocol"
- const char* prot;
- if (*handler != '/') {
- prot = handler;
- }
- else {
- prot = resource;
- path = handler;
- }
-
- // 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 and store in member.
- if (ssl_only)
- m_priv->m_handlerURL.assign("https://");
- else
- m_priv->m_handlerURL.assign(prot, colon-prot);
-
- // create the "host" from either the colon/slash or from the target string
- // If prot == handler then we're in either #1 or #2, else #3.
- // If slash == colon then we're in #2.
- if (prot != handler || slash == colon) {
- colon = strchr(resource, ':');
- colon += 3; // Get past the ://
- slash = strchr(colon, '/');
- }
- string host(colon, (slash ? slash-colon : strlen(colon)));
-
- // Build the handler URL
- m_priv->m_handlerURL+=host + path;
- return m_priv->m_handlerURL;
-}
-
-void ShibTarget::log(ShibLogLevel level, const string& msg)
-{
- Category::getInstance("shibtarget.ShibTarget").log(
- (level == LogLevelDebug ? Priority::DEBUG :
- (level == LogLevelInfo ? Priority::INFO :
- (level == LogLevelWarn ? Priority::WARN : Priority::ERROR))),
- msg
- );
-}
-
const IApplication* ShibTarget::getApplication() const
{
return m_priv->m_app;
return m_priv->m_conf;
}
-void* ShibTarget::returnDecline(void)
+long ShibTarget::returnDecline(void)
{
return NULL;
}
-void* ShibTarget::returnOK(void)
+long ShibTarget::returnOK(void)
{
return NULL;
}
*/
ShibTargetPriv::ShibTargetPriv()
- : m_app(NULL), m_mapper(NULL), m_conf(NULL), m_Config(NULL), m_cacheEntry(NULL), m_cgiParser(NULL) {}
+ : m_app(NULL), m_mapper(NULL), m_conf(NULL), m_Config(NULL), m_cacheEntry(NULL) {}
ShibTargetPriv::~ShibTargetPriv()
{
m_conf = NULL;
}
- delete m_cgiParser;
m_app = NULL;
m_Config = NULL;
}
m_mapper->lock();
// Obtain the application settings from the parsed URL
- m_settings = m_mapper->getSettings(st);
+ m_settings = m_mapper->getSettings(*st);
// Now find the application from the URL settings
pair<bool,const char*> application_id=m_settings.first->getString("applicationId");
- m_app=m_conf->getApplication(application_id.second);
+ m_app=dynamic_cast<const IApplication*>(m_conf->getApplication(application_id.second));
if (!m_app) {
m_mapper->unlock();
m_mapper = NULL;
st->m_url += uri;
}
-void* ShibTargetPriv::sendError(
+long ShibTargetPriv::sendError(
ShibTarget* st, const char* page, ExtTemplateParameters& tp, const XMLToolingException* ex
)
{
- ShibTarget::header_t hdrs[] = {
- ShibTarget::header_t("Expires","01-Jan-1997 12:00:00 GMT"),
- ShibTarget::header_t("Cache-Control","private,no-store,no-cache")
- };
-
+ st->setContentType("text/html");
+ st->setResponseHeader("Expires","01-Jan-1997 12:00:00 GMT");
+ st->setResponseHeader("Cache-Control","private,no-store,no-cache");
+
TemplateEngine* engine = XMLToolingConfig::getConfig().getTemplateEngine();
const PropertySet* props=m_app->getPropertySet("Errors");
if (props) {
ifstream infile(p.second);
if (infile) {
tp.setPropertySet(props);
- ostringstream ostr;
- engine->run(infile, ostr, tp, ex);
- return st->sendPage(ostr.str().c_str(), 200, "text/html", ArrayIterator<ShibTarget::header_t>(hdrs,2));
+ stringstream str;
+ engine->run(infile, str, tp, ex);
+ return st->sendResponse(str);
}
}
- else if (!strcmp(page,"access"))
- return st->sendPage("Access Denied", 403, "text/html", ArrayIterator<ShibTarget::header_t>(hdrs,2));
+ else if (!strcmp(page,"access")) {
+ istringstream msg("Access Denied");
+ return static_cast<opensaml::GenericResponse*>(st)->sendResponse(msg, opensaml::HTTPResponse::SAML_HTTP_STATUS_FORBIDDEN);
+ }
}
string errstr = string("sendError could not process error template (") + page + ") for application (";
errstr += m_app->getId();
errstr += ")";
- st->log(ShibTarget::LogLevelError, errstr);
- return st->sendPage(
- "Internal Server Error. Please contact the site administrator.", 500, "text/html", ArrayIterator<ShibTarget::header_t>(hdrs,2)
- );
+ st->log(SPRequest::SPError, errstr);
+ istringstream msg("Internal Server Error. Please contact the site administrator.");
+ return st->sendError(msg);
}
void ShibTargetPriv::clearHeaders(ShibTarget* st)
}
}
}
-
-/*************************************************************************
- * CGI Parser implementation
- */
-
-CgiParse::CgiParse(const ShibTarget* st)
-{
- const char* pch=NULL;
- if (!strcmp(st->getRequestMethod(),"POST"))
- pch=st->getRequestBody();
- else
- pch=st->getQueryString();
- size_t cl=pch ? strlen(pch) : 0;
-
-
- while (cl && pch) {
- char *name;
- char *value;
- value=fmakeword('&',&cl,&pch);
- plustospace(value);
- opensaml::SAMLConfig::getConfig().getURLEncoder()->decode(value);
- name=makeword(value,'=');
- kvp_map.insert(pair<string,char*>(name,value));
- free(name);
- }
-}
-
-CgiParse::~CgiParse()
-{
- for (multimap<string,char*>::iterator i=kvp_map.begin(); i!=kvp_map.end(); i++)
- free(i->second);
-}
-
-pair<CgiParse::walker,CgiParse::walker> CgiParse::get_values(const char* name) const
-{
- return kvp_map.equal_range(name);
-}
-
-/* Parsing routines modified from NCSA source. */
-char* CgiParse::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* CgiParse::fmakeword(char stop, size_t *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;
- }
-}
-
-void CgiParse::plustospace(char *str)
-{
- register int x;
-
- for(x=0;str[x];x++)
- if(str[x] == '+') str[x] = ' ';
-}
#define SHIB_TARGET_H
// New headers
-#include <shibsp/ListenerService.h>
+#include <shibsp/AbstractSPRequest.h>
+#include <shibsp/Application.h>
#include <shibsp/ServiceProvider.h>
-#include <saml/saml2/metadata/MetadataProvider.h>
-#include <xmltooling/security/TrustEngine.h>
+#include <shibsp/remoting/ListenerService.h>
// Old headers
#include <saml/saml.h>
virtual ~IHandler() {}
virtual const shibsp::PropertySet* getProperties() const { return m_props; }
virtual void setProperties(const shibsp::PropertySet* properties) { m_props=properties; }
- virtual std::pair<bool,void*> run(ShibTarget* st, bool isHandler=true) const=0;
+ virtual std::pair<bool,long> run(ShibTarget* st, bool isHandler=true) const=0;
private:
const shibsp::PropertySet* m_props;
};
* Application. Implementations should always expose an application named "default"
* as a last resort.
*/
- struct SHIBTARGET_EXPORTS IApplication : public virtual shibsp::PropertySet,
+ struct SHIBTARGET_EXPORTS IApplication : public virtual shibsp::Application,
public virtual shibboleth::ShibBrowserProfile::ITokenValidator
{
- virtual const char* getId() const=0;
- virtual const char* getHash() const=0;
-
virtual saml::Iterator<saml::SAMLAttributeDesignator*> getAttributeDesignators() const=0;
virtual saml::Iterator<shibboleth::IAAP*> getAAPProviders() const=0;
- virtual opensaml::saml2md::MetadataProvider* getMetadataProvider() const=0;
- virtual xmltooling::TrustEngine* getTrustEngine() const=0;
virtual saml::Iterator<const XMLCh*> getAudiences() const=0;
- virtual const shibsp::PropertySet* getCredentialUse(const opensaml::saml2md::EntityDescriptor* provider) const=0;
// caller is borrowing object, must use within scope of config lock
virtual const saml::SAMLBrowserProfile* getBrowserProfile() const=0;
#define ODBC_REPLAYCACHE "edu.internet2.middleware.shibboleth.sp.provider.ODBCReplayCacheProvider"
- /**
- * Interface to an access control plugin
- *
- * Access control plugins return authorization decisions based on the intersection
- * of the resource request and the active session. They can be implemented through
- * cross-platform or platform-specific mechanisms.
- */
- struct SHIBTARGET_EXPORTS IAccessControl : public virtual xmltooling::Lockable, public virtual saml::IPlugIn
- {
- virtual bool authorized(ShibTarget* st, ISessionCacheEntry* entry) const=0;
- virtual ~IAccessControl() {}
- };
-
- #define HTACCESS_ACCESSCONTROL "edu.internet2.middleware.shibboleth.sp.apache.provider.htAccessControl"
- #define XML_ACCESSCONTROL "edu.internet2.middleware.shibboleth.sp.provider.XMLAccessControl"
-
- /**
- * Interface to a request mapping plugin
- *
- * Request mapping plugins return configuration settings that apply to resource requests.
- * They can be implemented through cross-platform or platform-specific mechanisms.
- */
- struct SHIBTARGET_EXPORTS IRequestMapper : public virtual xmltooling::Lockable, public virtual saml::IPlugIn
- {
- typedef std::pair<const shibsp::PropertySet*,IAccessControl*> Settings;
- virtual Settings getSettings(ShibTarget* st) const=0;
- virtual ~IRequestMapper() {}
- };
-
- #define XML_REQUESTMAP_PROVIDER "edu.internet2.middleware.shibboleth.sp.provider.XMLRequestMapProvider"
- #define NATIVE_REQUESTMAP_PROVIDER "edu.internet2.middleware.shibboleth.sp.provider.NativeRequestMapProvider"
- #define LEGACY_REQUESTMAP_PROVIDER "edu.internet2.middleware.shibboleth.target.provider.XMLRequestMap"
-
struct SHIBTARGET_EXPORTS IConfig : public virtual shibsp::ServiceProvider
{
virtual ISessionCache* getSessionCache() const=0;
virtual saml::IReplayCache* getReplayCache() const=0;
- virtual IRequestMapper* getRequestMapper() const=0;
- virtual const IApplication* getApplication(const char* applicationId) const=0;
virtual ~IConfig() {}
};
};
class ShibTargetPriv;
- class SHIBTARGET_EXPORTS ShibTarget {
+ class SHIBTARGET_EXPORTS ShibTarget : public shibsp::AbstractSPRequest {
public:
ShibTarget(const IApplication* app);
virtual ~ShibTarget(void);
- // These are defined here so the subclass does not need to specifically
- // depend on log4cpp. We could use log4cpp::Priority::PriorityLevel
- // but this is just as easy, IMHO. It's just a case statement in the
- // implementation to handle the event level.
- enum ShibLogLevel {
- LogLevelDebug,
- LogLevelInfo,
- LogLevelWarn,
- LogLevelError
- };
-
- //
- // Note: subclasses MUST implement ALL of these virtual methods
- //
-
- // Send a message to the Webserver log
- virtual void log(ShibLogLevel level, const std::string &msg)=0;
-
- void log(ShibLogLevel level, const char* msg) {
- std::string s = msg;
- log(level, s);
- }
-
- // Get/Set a cookie for this request
- virtual std::string getCookies() const=0;
- virtual void setCookie(const std::string& name, const std::string& value)=0;
- virtual const char* getCookie(const std::string& name) const;
- void setCookie(const char* name, const char* value) {
- std::string ns = name;
- std::string vs = value;
- setCookie(ns, vs);
- }
- void setCookie(const char* name, const std::string& value) {
- std::string ns = name;
- setCookie(ns, value);
- }
-
- // Get any URL-encoded arguments or the raw POST body from the server
- virtual const char* getQueryString() const=0;
- virtual const char* getRequestBody() const=0;
- virtual const char* getRequestParameter(const char* param, size_t index=0) const;
-
- // Clear a header, set a header
- // These APIs are used for exporting the Assertions into the
- // Headers. It will clear some well-known headers first to make
- // sure none remain. Then it will process the set of assertions
- // and export them via setHeader().
- virtual void clearHeader(const std::string& name)=0;
- virtual void setHeader(const std::string& name, const std::string& value)=0;
- virtual std::string getHeader(const std::string& name)=0;
- virtual void setRemoteUser(const std::string& user)=0;
- virtual std::string getRemoteUser()=0;
-
- void clearHeader(const char* n) {
- std::string s = n;
- clearHeader(s);
- }
- void setHeader(const char* n, const char* v) {
- std::string ns = n;
- std::string vs = v;
- setHeader(ns, vs);
- }
- void setHeader(const std::string& n, const char* v) {
- std::string vs = v;
- setHeader(n, vs);
- }
- void setHeader(const char* n, const std::string& v) {
- std::string ns = n;
- setHeader(ns, v);
- }
- std::string getHeader(const char* n) {
- std::string s = n;
- return getHeader(s);
- }
- void setRemoteUser(const char* n) {
- std::string s = n;
- setRemoteUser(s);
- }
-
- // We're done. Finish up. Send specific result content or a redirect.
- // If there are no headers supplied assume the content-type is text/html
- typedef std::pair<std::string, std::string> header_t;
- virtual void* sendPage(
- const std::string& msg,
- int code = 200,
- const std::string& content_type = "text/html",
- const saml::Iterator<header_t>& headers = EMPTY(header_t)
- )=0;
- void* sendPage(const char* msg) {
- std::string m = msg;
- return sendPage(m);
- }
- virtual void* sendRedirect(const std::string& url)=0;
-
// These next two APIs are used to obtain the module-specific "OK"
// and "Decline" results. OK means "we believe that this request
// should be accepted". Declined means "we believe that this is
// not a shibbolized request so we have no comment".
- virtual void* returnDecline();
- virtual void* returnOK();
+ virtual long returnDecline();
+ virtual long returnOK();
//
// Note: Subclasses need not implement anything below this line
// automatically call doHandlePOST() when it encounters a request for
// the ShireURL; if false it will call returnOK() instead.
//
- std::pair<bool,void*> doCheckAuthN(bool handler = false);
- std::pair<bool,void*> doHandler();
- std::pair<bool,void*> doCheckAuthZ();
- std::pair<bool,void*> doExportAssertions(bool requireSession = true);
+ std::pair<bool,long> doCheckAuthN(bool handler = false);
+ std::pair<bool,long> doHandler();
+ std::pair<bool,long> doCheckAuthZ();
+ std::pair<bool,long> doExportAssertions(bool requireSession = true);
// Basic request access in case any plugins need the info
virtual const IConfig* getConfig() const;
virtual const IApplication* getApplication() const;
- const char* getRequestMethod() const {return m_method.c_str();}
- const char* getProtocol() const {return m_protocol.c_str();}
- const char* getHostname() const {return m_hostname.c_str();}
- int getPort() const {return m_port;}
- const char* getRequestURI() const {return m_uri.c_str();}
- const char* getContentType() const {return m_content_type.c_str();}
- const char* getRemoteAddr() const {return m_remote_addr.c_str();}
const char* getRequestURL() const {return m_url.c_str();}
- // Advanced methods useful to profile handlers implemented outside core
-
- // Get per-application session and state cookie name and properties
- virtual std::pair<std::string,const char*> getCookieNameProps(const char* prefix) const;
-
- // Determine the effective handler URL based on the resource URL
- virtual std::string getHandlerURL(const char* resource) const;
-
protected:
ShibTarget();
// Internal APIs
// Initialize the request from the parsed URL
- // protocol == http, https, etc
+ // scheme == http, https, etc
// hostname == server name
// port == server port
// uri == resource path
// method == GET, POST, etc.
void init(
- const char* protocol,
+ const char* scheme,
const char* hostname,
int port,
const char* uri,
const char* method
);
- std::string m_url, m_method, m_protocol, m_hostname, m_uri, m_content_type, m_remote_addr;
+ std::string m_url, m_method, m_scheme, m_hostname, m_uri, m_content_type, m_remote_addr;
int m_port;
private:
RelativePath="ShibHTTPHook.cpp"
>
</File>
- <File
- RelativePath="XMLRequestMapper.cpp"
- >
- </File>
</Files>
<Globals>
</Globals>
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * AbstractSPRequest.cpp
+ *
+ * Abstract base for SPRequest implementations
+ */
+
+#include "internal.h"
+#include "AbstractSPRequest.h"
+#include "Application.h"
+#include "util/CGIParser.h"
+
+#include <log4cpp/Category.hh>
+
+using namespace shibsp;
+using namespace xmltooling;
+using namespace log4cpp;
+using namespace std;
+
+AbstractSPRequest::AbstractSPRequest(const Application* app)
+ : m_app(app), m_log(&Category::getInstance(SHIBSP_LOGCAT)), m_parser(NULL)
+{
+ if (m_app)
+ return;
+}
+
+AbstractSPRequest::~AbstractSPRequest()
+{
+ delete m_parser;
+}
+
+const char* AbstractSPRequest::getParameter(const char* name) const
+{
+ if (!m_parser)
+ m_parser=new CGIParser(*this);
+
+ pair<CGIParser::walker,CGIParser::walker> bounds=m_parser->getParameters(name);
+ return (bounds.first==bounds.second) ? NULL : bounds.first->second;
+}
+
+vector<const char*>::size_type AbstractSPRequest::getParameters(const char* name, vector<const char*>& values) const
+{
+ if (!m_parser)
+ m_parser=new CGIParser(*this);
+
+ pair<CGIParser::walker,CGIParser::walker> bounds=m_parser->getParameters(name);
+ while (bounds.first!=bounds.second) {
+ values.push_back(bounds.first->second);
+ ++bounds.first;
+ }
+ return values.size();
+}
+
+const char* AbstractSPRequest::getCookie(const char* name) const
+{
+ if (m_cookieMap.empty()) {
+ string cookies=getHeader("Cookie");
+
+ string::size_type pos=0,cname,namelen,val,vallen;
+ while (pos !=string::npos && pos < cookies.length()) {
+ while (isspace(cookies[pos])) pos++;
+ cname=pos;
+ pos=cookies.find_first_of("=",pos);
+ if (pos == string::npos)
+ break;
+ namelen=pos-cname;
+ pos++;
+ if (pos==cookies.length())
+ break;
+ val=pos;
+ pos=cookies.find_first_of(";",pos);
+ if (pos != string::npos) {
+ vallen=pos-val;
+ pos++;
+ m_cookieMap.insert(make_pair(cookies.substr(cname,namelen),cookies.substr(val,vallen)));
+ }
+ else
+ m_cookieMap.insert(make_pair(cookies.substr(cname,namelen),cookies.substr(val)));
+ }
+ }
+ map<string,string>::const_iterator lookup=m_cookieMap.find(name);
+ return (lookup==m_cookieMap.end()) ? NULL : lookup->second.c_str();
+}
+
+const char* AbstractSPRequest::getHandlerURL(const char* resource) const
+{
+ if (!m_handlerURL.empty() && resource && !strcmp(getRequestURL(),resource))
+ return m_handlerURL.c_str();
+
+#ifdef HAVE_STRCASECMP
+ if (!resource || (strncasecmp(resource,"http://",7) && strncasecmp(resource,"https://",8)))
+#else
+ if (!resource || (strnicmp(resource,"http://",7) && strnicmp(resource,"https://",8)))
+#endif
+ throw ConfigurationException("Target resource was not an absolute URL.");
+
+ bool ssl_only=false;
+ const char* handler=NULL;
+ const PropertySet* props=m_app->getPropertySet("Sessions");
+ if (props) {
+ pair<bool,bool> p=props->getBool("handlerSSL");
+ if (p.first)
+ ssl_only=p.second;
+ pair<bool,const char*> p2=props->getString("handlerURL");
+ if (p2.first)
+ handler=p2.second;
+ }
+
+ // Should never happen...
+ if (!handler || (*handler!='/' && strncmp(handler,"http:",5) && strncmp(handler,"https:",6)))
+ throw ConfigurationException(
+ "Invalid handlerURL property ($1) in Application ($2)",
+ params(2, handler ? handler : "null", m_app->getId())
+ );
+
+ // The "handlerURL" property can be in one of three formats:
+ //
+ // 1) a full URI: http://host/foo/bar
+ // 2) a hostless URI: http:///foo/bar
+ // 3) a relative path: /foo/bar
+ //
+ // # Protocol Host Path
+ // 1 handler handler handler
+ // 2 handler resource handler
+ // 3 resource resource handler
+ //
+ // note: if ssl_only is true, make sure the protocol is https
+
+ const char* path = NULL;
+
+ // Decide whether to use the handler or the resource for the "protocol"
+ const char* prot;
+ if (*handler != '/') {
+ prot = handler;
+ }
+ else {
+ prot = resource;
+ path = handler;
+ }
+
+ // 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 and store in member.
+ if (ssl_only)
+ m_handlerURL.assign("https://");
+ else
+ m_handlerURL.assign(prot, colon-prot);
+
+ // create the "host" from either the colon/slash or from the target string
+ // If prot == handler then we're in either #1 or #2, else #3.
+ // If slash == colon then we're in #2.
+ if (prot != handler || slash == colon) {
+ colon = strchr(resource, ':');
+ colon += 3; // Get past the ://
+ slash = strchr(colon, '/');
+ }
+ string host(colon, (slash ? slash-colon : strlen(colon)));
+
+ // Build the handler URL
+ m_handlerURL += host + path;
+ return m_handlerURL.c_str();
+}
+
+void AbstractSPRequest::log(SPLogLevel level, const std::string& msg) const
+{
+ reinterpret_cast<Category*>(m_log)->log(
+ (level == SPDebug ? log4cpp::Priority::DEBUG :
+ (level == SPInfo ? log4cpp::Priority::INFO :
+ (level == SPWarn ? log4cpp::Priority::WARN :
+ (level == SPError ? log4cpp::Priority::ERROR : log4cpp::Priority::CRIT)))),
+ msg
+ );
+}
+
+bool AbstractSPRequest::isPriorityEnabled(SPLogLevel level) const
+{
+ return reinterpret_cast<Category*>(m_log)->isPriorityEnabled(
+ (level == SPDebug ? log4cpp::Priority::DEBUG :
+ (level == SPInfo ? log4cpp::Priority::INFO :
+ (level == SPWarn ? log4cpp::Priority::WARN :
+ (level == SPError ? log4cpp::Priority::ERROR : log4cpp::Priority::CRIT))))
+ );
+}
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file shibsp/AbstractSPRequest.h
+ *
+ * Abstract base for SPRequest implementations
+ */
+
+#ifndef __shibsp_abstreq_h__
+#define __shibsp_abstreq_h__
+
+#include <shibsp/exceptions.h>
+#include <shibsp/SPRequest.h>
+
+namespace shibsp {
+
+ class SHIBSP_API CGIParser;
+
+ /**
+ * Abstract base for SPRequest implementations
+ */
+ class SHIBSP_API AbstractSPRequest : public virtual SPRequest
+ {
+ protected:
+ /**
+ * Constructor
+ *
+ * @param app pointer to effective Application, if known
+ */
+ AbstractSPRequest(const Application* app=NULL);
+
+ public:
+ virtual ~AbstractSPRequest();
+
+ const Application& getSPApplication() const {
+ return *m_app;
+ }
+
+ const char* getParameter(const char* name) const;
+
+ std::vector<const char*>::size_type getParameters(const char* name, std::vector<const char*>& values) const;
+
+ const char* getCookie(const char* name) const;
+
+ const char* getHandlerURL(const char* resource=NULL) const;
+
+ void log(SPLogLevel level, const std::string& msg) const;
+
+ bool isPriorityEnabled(SPLogLevel level) const;
+
+ protected:
+ /** Holds effective Application. */
+ const Application* m_app;
+
+ private:
+ void* m_log; // declared void* to avoid log4cpp header conflicts in Apache
+ mutable std::string m_handlerURL;
+ mutable std::map<std::string,std::string> m_cookieMap;
+ mutable CGIParser* m_parser;
+ };
+};
+
+#endif /* __shibsp_abstreq_h__ */
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file shibsp/AccessControl.h
+ *
+ * Interface to an access control plugin
+ */
+
+#ifndef __shibsp_acl_h__
+#define __shibsp_acl_h__
+
+#include <shibsp/base.h>
+#include <xmltooling/Lockable.h>
+
+namespace shibsp {
+
+ class SHIBSP_API Session;
+ class SHIBSP_API SPRequest;
+
+ /**
+ * Interface to an access control plugin
+ *
+ * Access control plugins return authorization decisions based on the intersection
+ * of the resource request and the active session. They can be implemented through
+ * cross-platform or platform-specific mechanisms.
+ */
+ class SHIBSP_API AccessControl : public virtual xmltooling::Lockable
+ {
+ MAKE_NONCOPYABLE(AccessControl);
+ protected:
+ AccessControl() {}
+ public:
+ virtual ~AccessControl() {}
+
+ /**
+ * Perform an authorization check.
+ *
+ * @param request SP request information
+ * @param session active user session, if any
+ * @return true iff access should be granted
+ */
+ virtual bool authorized(SPRequest& request, Session* session) const=0;
+ };
+
+ /**
+ * Registers AccessControl classes into the runtime.
+ */
+ void SHIBSP_API registerAccessControls();
+
+ /** AccessControl based on rudimentary XML syntax. */
+ #define XML_ACCESS_CONTROL "edu.internet2.middleware.shibboleth.sp.provider.XMLAccessControl"
+
+ /** Reserved for Apache-style .htaccess support. */
+ #define HT_ACCESS_CONTROL "edu.internet2.middleware.shibboleth.sp.apache.provider.htAccessControl"
+};
+
+#endif /* __shibsp_acl_h__ */
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Application.cpp
+ *
+ * Interface to a Shibboleth Application instance.
+ */
+
+#include "internal.h"
+#include "Application.h"
+
+using namespace shibsp;
+using namespace std;
+
+pair<string,const char*> Application::getCookieNameProps(const char* prefix) const
+{
+ static const char* defProps="; path=/";
+
+ const PropertySet* props=getPropertySet("Sessions");
+ if (props) {
+ pair<bool,const char*> p=props->getString("cookieProps");
+ if (!p.first)
+ p.second=defProps;
+ pair<bool,const char*> p2=props->getString("cookieName");
+ if (p2.first)
+ return make_pair(string(prefix) + p2.second,p.second);
+ return make_pair(string(prefix) + getHash(),p.second);
+ }
+
+ // Shouldn't happen, but just in case..
+ return pair<string,const char*>(prefix,defProps);
+}
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file shibsp/Application.h
+ *
+ * Interface to a Shibboleth Application instance.
+ */
+
+#ifndef __shibsp_app_h__
+#define __shibsp_app_h__
+
+#include <shibsp/util/PropertySet.h>
+#include <saml/saml2/metadata/MetadataProvider.h>
+#include <xmltooling/security/TrustEngine.h>
+
+namespace shibsp {
+
+ /**
+ * Interface to a Shibboleth Application instance.
+ *
+ * <p>An Application is a logical set of resources that act as a unit
+ * of session management and policy.
+ */
+ class SHIBSP_API Application : public virtual PropertySet
+ {
+ MAKE_NONCOPYABLE(Application);
+ protected:
+ Application() {}
+ public:
+ virtual ~Application() {}
+
+ /**
+ * Returns the Application's ID.
+ *
+ * @return the ID
+ */
+ virtual const char* getId() const=0;
+
+ /**
+ * Returns a unique hash for the Application.
+ *
+ * @return a value resulting from a hash of the Application's ID
+ */
+ virtual const char* getHash() const=0;
+
+ /**
+ * Returns the name and cookie properties to use for this Application.
+ *
+ * @param prefix a value to prepend to the base cookie name
+ * @return a pair containing the cookie name and the string to append to the cookie value
+ */
+ virtual std::pair<std::string,const char*> getCookieNameProps(const char* prefix) const;
+
+ /**
+ * Returns a MetadataProvider for use with this Application.
+ *
+ * @return a MetadataProvider instance, or NULL
+ */
+ virtual opensaml::saml2md::MetadataProvider* getMetadataProvider() const=0;
+
+ /**
+ * Returns a TrustEngine for use with this Application.
+ *
+ * @return a TrustEngine instance, or NULL
+ */
+ virtual xmltooling::TrustEngine* getTrustEngine() const=0;
+
+ /**
+ * Returns configuration properties governing security interactions with a peer entity.
+ *
+ * @param provider a peer entity's metadata
+ * @return the applicable PropertySet
+ */
+ virtual const shibsp::PropertySet* getCredentialUse(const opensaml::saml2md::EntityDescriptor* provider) const=0;
+ };
+};
+
+#endif /* __shibsp_app_h__ */
libshibspincludedir = $(includedir)/shibsp
+mdincludedir = $(includedir)/shibsp/metadata
+
+remincludedir = $(includedir)/shibsp/remoting
+
+secincludedir = $(includedir)/shibsp/security
+
+utilincludedir = $(includedir)/shibsp/util
+
libshibspinclude_HEADERS = \
+ AbstractSPRequest.h \
+ AccessControl.h \
+ Application.h \
base.h \
- ddf.h \
- DOMPropertySet.h \
exceptions.h \
- ListenerService.h \
- MetadataExt.h \
paths.h \
- PKIXTrustEngine.h \
- PropertySet.h \
- version.h \
+ RequestMapper.h \
ServiceProvider.h \
- SocketListener.h \
+ SessionCache.h \
SPConfig.h \
- SPConstants.h
+ SPRequest.h \
+ version.h
+
+mdinclude_HEADERS = \
+ metadata/MetadataExt.h
+
+reminclude_HEADERS = \
+ ddf.h \
+ ListenerService.h
+
+secinclude_HEADERS = \
+ security/PKIXTrustEngine.h
+
+utilinclude_HEADERS = \
+ util/DOMPropertySet.h \
+ util/PropertySet.h \
+ util/SPConstants.h
noinst_HEADERS = \
- internal.h
+ internal.h \
+ remoting/impl/SocketListener.h
libshibsp_la_SOURCES = \
- ddf.cpp \
- DOMPropertySet.cpp \
- ListenerService.cpp \
- MetadataExtImpl.cpp \
- MetadataExtSchemaValidators.cpp \
- PKIXTrustEngine.cpp \
+ AbstractSPRequest.cpp \
+ Application.cpp \
ServiceProvider.cpp \
SPConfig.cpp \
- SPConstants.cpp \
- SocketListener.cpp \
- TCPListener.cpp \
- UnixListener.cpp
+ impl/XMLAccessControl.cpp \
+ impl/XMLRequestMapper.cpp \
+ metadata/MetadataExtImpl.cpp \
+ metadata/MetadataExtSchemaValidators.cpp \
+ remoting/impl/ddf.cpp \
+ remoting/impl/ListenerService.cpp \
+ remoting/impl/SocketListener.cpp \
+ remoting/impl/TCPListener.cpp \
+ remoting/impl/UnixListener.cpp \
+ security/PKIXTrustEngine.cpp \
+ util/DOMPropertySet.cpp \
+ util/SPConstants.cpp
# this is different from the project version
# http://sources.redhat.com/autobook/autobook/autobook_91.html
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file shibsp/RequestMapper.h
+ *
+ * Interface to a request mapping plugin
+ */
+
+#ifndef __shibsp_reqmap_h__
+#define __shibsp_reqmap_h__
+
+#include <shibsp/base.h>
+#include <xmltooling/Lockable.h>
+
+namespace shibsp {
+
+ class SHIBSP_API AccessControl;
+ class SHIBSP_API PropertySet;
+ class SHIBSP_API SPRequest;
+
+ /**
+ * Interface to a request mapping plugin
+ *
+ * Request mapping plugins return configuration settings that apply to resource requests.
+ * They can be implemented through cross-platform or platform-specific mechanisms.
+ */
+ class SHIBSP_API RequestMapper : public virtual xmltooling::Lockable
+ {
+ MAKE_NONCOPYABLE(RequestMapper);
+ protected:
+ RequestMapper() {}
+ public:
+ virtual ~RequestMapper() {}
+
+ /** Combination of configuration settings and effective access control. */
+ typedef std::pair<const PropertySet*,AccessControl*> Settings;
+
+ /**
+ * Map request to settings.
+ *
+ * @param request SP request
+ * @return configuration settings and effective AccessControl plugin, if any
+ */
+ virtual Settings getSettings(const SPRequest& request) const=0;
+ };
+
+ /**
+ * Registers RequestMapper classes into the runtime.
+ */
+ void SHIBSP_API registerRequestMappers();
+
+ /** XML-based RequestMapper implementation. */
+ #define XML_REQUEST_MAPPER "edu.internet2.middleware.shibboleth.sp.provider.XMLRequestMapProvider"
+
+ /** Hybrid of XML and platform-specific configuration. */
+ #define NATIVE_REQUEST_MAPPER "edu.internet2.middleware.shibboleth.sp.provider.NativeRequestMapProvider"
+};
+
+#endif /* __shibsp_reqmap_h__ */
#include "internal.h"
#include "exceptions.h"
-#include "ListenerService.h"
-#include "MetadataExt.h"
-#include "PKIXTrustEngine.h"
+#include "AccessControl.h"
+#include "RequestMapper.h"
#include "ServiceProvider.h"
#include "SPConfig.h"
+#include "metadata/MetadataExt.h"
+#include "remoting/ListenerService.h"
+#include "security/PKIXTrustEngine.h"
#include <log4cpp/Category.hh>
#include <saml/SAMLConfig.h>
registerMetadataExtClasses();
registerPKIXTrustEngine();
+ registerAccessControls();
registerListenerServices();
+ registerRequestMappers();
registerServiceProviders();
log.info("library initialization complete");
delete m_serviceProvider;
m_serviceProvider = NULL;
- ListenerServiceManager.deregisterFactories();
ServiceProviderManager.deregisterFactories();
+ RequestMapperManager.deregisterFactories();
+ ListenerServiceManager.deregisterFactories();
+ AccessControlManager.deregisterFactories();
SAMLConfig::getConfig().term();
log.info("library shutdown complete");
*/
namespace shibsp {
+ class SHIBSP_API AccessControl;
class SHIBSP_API ListenerService;
+ class SHIBSP_API RequestMapper;
class SHIBSP_API ServiceProvider;
#if defined (_MSC_VER)
Trust = 8,
Credentials = 16,
AAP = 32,
- RequestMapper = 64,
+ RequestMapping = 64,
OutOfProcess = 128,
InProcess = 256,
Logging = 512
}
/**
+ * Manages factories for AccessControl plugins.
+ */
+ xmltooling::PluginManager<AccessControl,const xercesc::DOMElement*> AccessControlManager;
+
+ /**
* Manages factories for ListenerService plugins.
*/
xmltooling::PluginManager<ListenerService,const xercesc::DOMElement*> ListenerServiceManager;
/**
+ * Manages factories for RequestMapper plugins.
+ */
+ xmltooling::PluginManager<RequestMapper,const xercesc::DOMElement*> RequestMapperManager;
+
+ /**
* Manages factories for ServiceProvider plugins.
*/
xmltooling::PluginManager<ServiceProvider,const xercesc::DOMElement*> ServiceProviderManager;
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file shibsp/SPRequest.h
+ *
+ * Interface to server request being processed
+ */
+
+#ifndef __shibsp_req_h__
+#define __shibsp_req_h__
+
+#include <shibsp/base.h>
+#include <saml/binding/HTTPRequest.h>
+#include <saml/binding/HTTPResponse.h>
+
+namespace shibsp {
+
+ class SHIBSP_API Application;
+
+ /**
+ * Interface to server request being processed
+ *
+ * <p>To supply information from the surrounding web server environment,
+ * a shim must be supplied in the form of this interface to adapt the
+ * library to different proprietary server APIs.
+ *
+ * <p>This interface need not be threadsafe.
+ */
+ class SHIBSP_API SPRequest : public virtual opensaml::HTTPRequest, public virtual opensaml::HTTPResponse
+ {
+ protected:
+ SPRequest() {}
+ public:
+ virtual ~SPRequest() {}
+
+ /**
+ * Returns the Application governing the request.
+ *
+ * @return reference to Application
+ */
+ virtual const Application& getSPApplication() const=0;
+
+ /**
+ * Returns the effective base Handler URL for a resource,
+ * or the current request URL.
+ *
+ * @param resource resource URL to compute handler for
+ * @return base location of handler
+ */
+ virtual const char* getHandlerURL(const char* resource=NULL) const=0;
+
+ /**
+ * Get a cookie value supplied by the client.
+ *
+ * @param name name of cookie
+ * @return cookie value or NULL
+ */
+ virtual const char* getCookie(const char* name) const=0;
+
+ /**
+ * Returns a non-spoofable request header value, if possible.
+ * Platforms that support environment export can redirect header
+ * lookups by overriding this method.
+ *
+ * @param name the name of the secure header to return
+ * @return the header's value, or an empty string
+ */
+ virtual std::string getSecureHeader(const char* name) const {
+ return getHeader(name);
+ }
+
+ /**
+ * Ensures no value exists for a request header.
+ *
+ * @param name name of header to clear
+ */
+ virtual void clearHeader(const char* name)=0;
+
+ /**
+ * Sets a value for a request header.
+ *
+ * @param name name of header to set
+ * @param value value to set
+ */
+ virtual void setHeader(const char* name, const char* value)=0;
+
+ /**
+ * Establish REMOTE_USER identity in request.
+ *
+ * @param user REMOTE_USER value to set or NULL to clear
+ */
+ virtual void setRemoteUser(const char* user)=0;
+
+ /** Portable logging levels. */
+ enum SPLogLevel {
+ SPDebug,
+ SPInfo,
+ SPWarn,
+ SPError,
+ SPCrit
+ };
+
+ /**
+ * Log to native server environment.
+ *
+ * @param level logging level
+ * @param msg message to log
+ */
+ virtual void log(SPLogLevel level, const std::string& msg) const=0;
+
+ /**
+ * Test logging level.
+ *
+ * @param level logging level
+ * @return true iff logging level is enabled
+ */
+ virtual bool isPriorityEnabled(SPLogLevel level) const=0;
+ };
+};
+
+#endif /* __shibsp_req_h__ */
{
//SPConfig::getConfig().ServiceProviderManager.registerFactory(XML_SERVICE_PROVIDER, XMLServiceProviderFactory);
}
+
+pair<bool,long> ServiceProvider::doAuthentication(SPRequest& request, bool handler) const
+{
+ return make_pair(true,0);
+}
+
+pair<bool,long> ServiceProvider::doAuthorization(SPRequest& request) const
+{
+ return make_pair(true,0);
+}
+
+pair<bool,long> ServiceProvider::doExport(SPRequest& request, bool requireSession) const
+{
+ return make_pair(true,0);
+}
+
+pair<bool,long> ServiceProvider::doHandler(SPRequest& request) const
+{
+ return make_pair(true,0);
+}
#ifndef __shibsp_sp_h__
#define __shibsp_sp_h__
-#include <shibsp/PropertySet.h>
+#include <shibsp/util/PropertySet.h>
#include <xmltooling/signature/CredentialResolver.h>
namespace shibsp {
- class ListenerService;
+ class SHIBSP_API Application;
+ class SHIBSP_API ListenerService;
+ class SHIBSP_API RequestMapper;
+ class SHIBSP_API SessionCache;
+ class SHIBSP_API SPRequest;
/**
* Interface to a Shibboleth ServiceProvider instance.
*/
virtual xmlsignature::CredentialResolver* getCredentialResolver(const char* id) const=0;
+ /**
+ * Returns a RequestMapper instance.
+ *
+ * @param a RequestMapper if available, or NULL
+ */
+ virtual RequestMapper* getRequestMapper() const=0;
+
//virtual ISessionCache* getSessionCache() const=0;
- //virtual IRequestMapper* getRequestMapper() const=0;
+ /**
+ * Returns an Application instance matching the specified ID.
+ *
+ * @param applicationId the ID of the application
+ * @return pointer to the application, or NULL
+ */
+ virtual const Application* getApplication(const char* applicationId) const=0;
+
+ /**
+ * Enforces requirements for an authenticated session.
+ *
+ * <p>If the return value's first member is true, then request processing should terminate
+ * with the second member as a status value. If false, processing can continue.
+ *
+ * @param request SP request interface
+ * @param handler true iff a request to a registered Handler location can be directly executed
+ * @return a pair containing a "request completed" indicator and a server-specific response code
+ */
+ virtual std::pair<bool,long> doAuthentication(SPRequest& request, bool handler=false) const;
+
+ /**
+ * Enforces authorization requirements based on the authenticated session.
+ *
+ * <p>If the return value's first member is true, then request processing should terminate
+ * with the second member as a status value. If false, processing can continue.
+ *
+ * @param request SP request interface
+ * @return a pair containing a "request completed" indicator and a server-specific response code
+ */
+ virtual std::pair<bool,long> doAuthorization(SPRequest& request) const;
- //virtual const IApplication* getApplication(const char* applicationId) const=0;
+ /**
+ * Publishes session contents to the request in the form of headers or environment variables.
+ *
+ * <p>If the return value's first member is true, then request processing should terminate
+ * with the second member as a status value. If false, processing can continue.
+ *
+ * @param request SP request interface
+ * @param requireSession set to true iff an error should result if no session exists
+ * @return a pair containing a "request completed" indicator and a server-specific response code
+ */
+ virtual std::pair<bool,long> doExport(SPRequest& request, bool requireSession=true) const;
+
+ /**
+ * Services requests for registered Handler locations.
+ *
+ * <p>If the return value's first member is true, then request processing should terminate
+ * with the second member as a status value. If false, processing can continue.
+ *
+ * @param request SP request interface
+ * @return a pair containing a "request completed" indicator and a server-specific response code
+ */
+ virtual std::pair<bool,long> doHandler(SPRequest& request) const;
};
/**
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file shibsp/SessionCache.h
+ *
+ * Caches and manages user sessions
+ */
+
+#ifndef __shibsp_sessioncache_h__
+#define __shibsp_sessioncache_h__
+
+#include <xmltooling/Lockable.h>
+#include <xercesc/dom/DOM.hpp>
+
+namespace shibsp {
+
+ class SHIBSP_API Session : public virtual xmltooling::Lockable
+ {
+ MAKE_NONCOPYABLE(Session);
+ protected:
+ Session() {}
+ virtual ~Session() {}
+ public:
+ /* TODO: design new interface, probably with version-specific subinterfaces
+ virtual const char* getClientAddress() const=0;
+ virtual const char* getProviderId() const=0;
+ virtual std::pair<const char*,const saml::SAMLSubject*> getSubject(bool xml=true, bool obj=false) const=0;
+ virtual const char* getAuthnContext() const=0;
+ virtual std::pair<const char*,const saml::SAMLResponse*> getTokens(bool xml=true, bool obj=false) const=0;
+ virtual std::pair<const char*,const saml::SAMLResponse*> getFilteredTokens(bool xml=true, bool obj=false) const=0;
+ */
+ };
+
+ /**
+ * Creates and manages user sessions
+ *
+ * The cache abstracts a persistent (meaning across requests) cache of
+ * instances of the Session interface. Creation of new entries and entry
+ * lookup are confined to this interface to enable the implementation to
+ * remote and/or optimize calls by implementing custom versions of the
+ * Session interface as required.
+ */
+ class SHIBSP_API SessionCache
+ {
+ MAKE_NONCOPYABLE(SessionCache);
+ public:
+ /**
+ * Constructor
+ */
+ SessionCache(const xercesc::DOMElement* e);
+
+ virtual ~SessionCache();
+
+ };
+};
+
+#endif /* __shibsp_sessioncache_h__ */
-/*
- * Copyright 2001-2005 Internet2
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* XMLAccessControl.cpp - an XML-based access control syntax
-
- Scott Cantor
- 10/25/05
-*/
-
-#include "internal.h"
-
-#include <algorithm>
-
-#include <shib-target/shib-target.h>
-#include <xmltooling/util/ReloadableXMLFile.h>
-#include <xmltooling/util/XMLHelper.h>
-
-#ifndef HAVE_STRCASECMP
-# define strcasecmp _stricmp
-#endif
-
-using namespace shibsp;
-using namespace shibtarget;
-using namespace saml;
-using namespace shibboleth;
-using namespace xmltooling;
-using namespace std;
-
-namespace {
- struct IAuthz {
- virtual ~IAuthz() {}
- virtual bool authorized(ShibTarget* st, ISessionCacheEntry* entry) const=0;
- };
-
- class Rule : public IAuthz
- {
- public:
- Rule(const DOMElement* e);
- ~Rule() {}
- bool authorized(ShibTarget* st, ISessionCacheEntry* entry) const;
-
- private:
- string m_alias;
- vector <string> m_vals;
- };
-
- class Operator : public IAuthz
- {
- public:
- Operator(const DOMElement* e);
- ~Operator();
- bool authorized(ShibTarget* st, ISessionCacheEntry* entry) const;
-
- private:
- enum operator_t { OP_NOT, OP_AND, OP_OR } m_op;
- vector<IAuthz*> m_operands;
- };
-
-#if defined (_MSC_VER)
- #pragma warning( push )
- #pragma warning( disable : 4250 )
-#endif
-
- class XMLAccessControl : public IAccessControl, public ReloadableXMLFile
- {
- public:
- XMLAccessControl(const DOMElement* e) : ReloadableXMLFile(e), m_rootAuthz(NULL) {
- load(); // guarantees an exception or the policy is loaded
- }
-
- ~XMLAccessControl() {
- delete m_rootAuthz;
- }
-
- bool authorized(ShibTarget* st, ISessionCacheEntry* entry) const;
-
- protected:
- pair<bool,DOMElement*> load();
-
- private:
- IAuthz* m_rootAuthz;
- };
-
-#if defined (_MSC_VER)
- #pragma warning( pop )
-#endif
-
- static const XMLCh AccessControl[] = UNICODE_LITERAL_13(A,c,c,e,s,s,C,o,n,t,r,o,l);
- static const XMLCh require[] = UNICODE_LITERAL_7(r,e,q,u,i,r,e);
- static const XMLCh NOT[] = UNICODE_LITERAL_3(N,O,T);
- static const XMLCh AND[] = UNICODE_LITERAL_3(A,N,D);
- static const XMLCh OR[] = UNICODE_LITERAL_2(O,R);
- static const XMLCh _Rule[] = UNICODE_LITERAL_4(R,u,l,e);
-}
-
-IPlugIn* XMLAccessControlFactory(const DOMElement* e)
-{
- return new XMLAccessControl(e);
-}
-
-Rule::Rule(const DOMElement* e)
-{
- xmltooling::auto_ptr_char req(e->getAttributeNS(NULL,require));
- if (!req.get() || !*req.get())
- throw ConfigurationException("Access control rule missing require attribute");
- m_alias=req.get();
-
- xmltooling::auto_ptr_char vals(e->hasChildNodes() ? e->getFirstChild()->getNodeValue() : NULL);
-#ifdef HAVE_STRTOK_R
- char* pos=NULL;
- const char* token=strtok_r(const_cast<char*>(vals.get()),"/",&pos);
-#else
- const char* token=strtok(const_cast<char*>(vals.get()),"/");
-#endif
- while (token) {
- m_vals.push_back(token);
-#ifdef HAVE_STRTOK_R
- token=strtok_r(NULL,"/",&pos);
-#else
- token=strtok(NULL,"/");
-#endif
- }
-}
-
-bool Rule::authorized(ShibTarget* st, ISessionCacheEntry* entry) const
-{
- // Map alias in rule to the attribute.
- Iterator<IAAP*> provs=st->getApplication()->getAAPProviders();
- AAP wrapper(provs,m_alias.c_str());
- if (wrapper.fail()) {
- st->log(ShibTarget::LogLevelWarn, string("AccessControl plugin didn't recognize rule (") + m_alias + "), check AAP for corresponding Alias");
- return false;
- }
- else if (!entry) {
- st->log(ShibTarget::LogLevelWarn, "AccessControl plugin not given a valid session to evaluate, are you using lazy sessions?");
- return false;
- }
-
- // Find the corresponding attribute. This isn't very efficient...
- pair<const char*,const SAMLResponse*> filtered=entry->getFilteredTokens(false,true);
- Iterator<SAMLAssertion*> a_iter(filtered.second ? filtered.second->getAssertions() : EMPTY(SAMLAssertion*));
- while (a_iter.hasNext()) {
- SAMLAssertion* assert=a_iter.next();
- Iterator<SAMLStatement*> statements=assert->getStatements();
- while (statements.hasNext()) {
- SAMLAttributeStatement* astate=dynamic_cast<SAMLAttributeStatement*>(statements.next());
- if (!astate)
- continue;
- Iterator<SAMLAttribute*> attrs=astate->getAttributes();
- while (attrs.hasNext()) {
- SAMLAttribute* attr=attrs.next();
- if (!XMLString::compareString(attr->getName(),wrapper->getName()) &&
- !XMLString::compareString(attr->getNamespace(),wrapper->getNamespace())) {
- // Now we have to intersect the attribute's values against the rule's list.
- Iterator<string> vals=attr->getSingleByteValues();
- if (!vals.hasNext())
- return false;
- for (vector<string>::const_iterator ival=m_vals.begin(); ival!=m_vals.end(); ival++) {
- vals.reset();
- while (vals.hasNext()) {
- const string& v=vals.next();
- if ((wrapper->getCaseSensitive() && v == *ival) || (!wrapper->getCaseSensitive() && !strcasecmp(v.c_str(),ival->c_str()))) {
- st->log(ShibTarget::LogLevelDebug, string("XMLAccessControl plugin expecting " + *ival + ", authz granted"));
- return true;
- }
- }
- }
- }
- }
- }
- }
-
- return false;
-}
-
-Operator::Operator(const DOMElement* e)
-{
- if (XMLString::equals(e->getLocalName(),NOT))
- m_op=OP_NOT;
- else if (XMLString::equals(e->getLocalName(),AND))
- m_op=OP_AND;
- else if (XMLString::equals(e->getLocalName(),OR))
- m_op=OP_OR;
- else
- throw ConfigurationException("Unrecognized operator in access control rule");
-
- try {
- e=XMLHelper::getFirstChildElement(e);
- if (XMLString::equals(e->getLocalName(),_Rule))
- m_operands.push_back(new Rule(e));
- else
- m_operands.push_back(new Operator(e));
-
- if (m_op==OP_NOT)
- return;
-
- e=XMLHelper::getNextSiblingElement(e);
- while (e) {
- if (XMLString::equals(e->getLocalName(),_Rule))
- m_operands.push_back(new Rule(e));
- else
- m_operands.push_back(new Operator(e));
- e=XMLHelper::getNextSiblingElement(e);
- }
- }
- catch (exception&) {
- for_each(m_operands.begin(),m_operands.end(),xmltooling::cleanup<IAuthz>());
- throw;
- }
-}
-
-Operator::~Operator()
-{
- for_each(m_operands.begin(),m_operands.end(),xmltooling::cleanup<IAuthz>());
-}
-
-bool Operator::authorized(ShibTarget* st, ISessionCacheEntry* entry) const
-{
- switch (m_op) {
- case OP_NOT:
- return !m_operands[0]->authorized(st,entry);
-
- case OP_AND:
- {
- for (vector<IAuthz*>::const_iterator i=m_operands.begin(); i!=m_operands.end(); i++) {
- if (!(*i)->authorized(st,entry))
- return false;
- }
- return true;
- }
-
- case OP_OR:
- {
- for (vector<IAuthz*>::const_iterator i=m_operands.begin(); i!=m_operands.end(); i++) {
- if ((*i)->authorized(st,entry))
- return true;
- }
- return false;
- }
- }
- st->log(ShibTarget::LogLevelWarn,"Unknown operation in access control policy, denying access");
- return false;
-}
-
-pair<bool,DOMElement*> XMLAccessControl::load()
-{
- // Load from source using base class.
- pair<bool,DOMElement*> raw = ReloadableXMLFile::load();
-
- // If we own it, wrap it.
- XercesJanitor<DOMDocument> docjanitor(raw.first ? raw.second->getOwnerDocument() : NULL);
-
- // Check for AccessControl wrapper and drop a level.
- if (XMLString::equals(raw.second->getLocalName(),AccessControl))
- raw.second = XMLHelper::getFirstChildElement(raw.second);
-
- IAuthz* authz;
- if (XMLString::equals(raw.second->getLocalName(),_Rule))
- authz=new Rule(raw.second);
- else
- authz=new Operator(raw.second);
-
- delete m_rootAuthz;
- m_rootAuthz = authz;
- return make_pair(false,(DOMElement*)NULL);
-}
-
-bool XMLAccessControl::authorized(ShibTarget* st, ISessionCacheEntry* entry) const
-{
- return m_rootAuthz ? m_rootAuthz->authorized(st,entry) : false;
-}
+/*\r
+ * Copyright 2001-2005 Internet2\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/**\r
+ * XMLAccessControl.cpp\r
+ *\r
+ * XML-based access control syntax\r
+ */\r
+\r
+#include "internal.h"\r
+#include "exceptions.h"\r
+#include "AccessControl.h"\r
+#include "SessionCache.h"\r
+\r
+#include <xmltooling/util/ReloadableXMLFile.h>\r
+#include <xmltooling/util/XMLHelper.h>\r
+#include <xercesc/util/XMLUniDefs.hpp>\r
+\r
+#ifndef HAVE_STRCASECMP\r
+# define strcasecmp _stricmp\r
+#endif\r
+\r
+using namespace shibsp;\r
+using namespace xmltooling;\r
+using namespace std;\r
+\r
+namespace {\r
+ \r
+ class Rule : public AccessControl\r
+ {\r
+ public:\r
+ Rule(const DOMElement* e);\r
+ ~Rule() {}\r
+\r
+ Lockable* lock() {return this;}\r
+ void unlock() {}\r
+\r
+ bool authorized(SPRequest& request, Session* session) const;\r
+ \r
+ private:\r
+ string m_alias;\r
+ vector <string> m_vals;\r
+ };\r
+ \r
+ class Operator : public AccessControl\r
+ {\r
+ public:\r
+ Operator(const DOMElement* e);\r
+ ~Operator();\r
+\r
+ Lockable* lock() {return this;}\r
+ void unlock() {}\r
+\r
+ bool authorized(SPRequest& request, Session* session) const;\r
+ \r
+ private:\r
+ enum operator_t { OP_NOT, OP_AND, OP_OR } m_op;\r
+ vector<AccessControl*> m_operands;\r
+ };\r
+\r
+#if defined (_MSC_VER)\r
+ #pragma warning( push )\r
+ #pragma warning( disable : 4250 )\r
+#endif\r
+\r
+ class XMLAccessControl : public AccessControl, public ReloadableXMLFile\r
+ {\r
+ public:\r
+ XMLAccessControl(const DOMElement* e) : ReloadableXMLFile(e), m_rootAuthz(NULL) {\r
+ load(); // guarantees an exception or the policy is loaded\r
+ }\r
+ \r
+ ~XMLAccessControl() {\r
+ delete m_rootAuthz;\r
+ }\r
+\r
+ bool authorized(SPRequest& request, Session* session) const;\r
+\r
+ protected:\r
+ pair<bool,DOMElement*> load();\r
+\r
+ private:\r
+ AccessControl* m_rootAuthz;\r
+ };\r
+\r
+#if defined (_MSC_VER)\r
+ #pragma warning( pop )\r
+#endif\r
+\r
+ AccessControl* SHIBSP_DLLLOCAL XMLAccessControlFactory(const DOMElement* const & e)\r
+ {\r
+ return new XMLAccessControl(e);\r
+ }\r
+\r
+ static const XMLCh _AccessControl[] = UNICODE_LITERAL_13(A,c,c,e,s,s,C,o,n,t,r,o,l);\r
+ static const XMLCh require[] = UNICODE_LITERAL_7(r,e,q,u,i,r,e);\r
+ static const XMLCh NOT[] = UNICODE_LITERAL_3(N,O,T);\r
+ static const XMLCh AND[] = UNICODE_LITERAL_3(A,N,D);\r
+ static const XMLCh OR[] = UNICODE_LITERAL_2(O,R);\r
+ static const XMLCh _Rule[] = UNICODE_LITERAL_4(R,u,l,e);\r
+}\r
+\r
+void SHIBSP_API shibsp::registerAccessControls()\r
+{\r
+ SPConfig::getConfig().AccessControlManager.registerFactory(XML_ACCESS_CONTROL, XMLAccessControlFactory);\r
+}\r
+\r
+Rule::Rule(const DOMElement* e)\r
+{\r
+ xmltooling::auto_ptr_char req(e->getAttributeNS(NULL,require));\r
+ if (!req.get() || !*req.get())\r
+ throw ConfigurationException("Access control rule missing require attribute");\r
+ m_alias=req.get();\r
+ \r
+ xmltooling::auto_ptr_char vals(e->hasChildNodes() ? e->getFirstChild()->getNodeValue() : NULL);\r
+#ifdef HAVE_STRTOK_R\r
+ char* pos=NULL;\r
+ const char* token=strtok_r(const_cast<char*>(vals.get()),"/",&pos);\r
+#else\r
+ const char* token=strtok(const_cast<char*>(vals.get()),"/");\r
+#endif\r
+ while (token) {\r
+ m_vals.push_back(token);\r
+#ifdef HAVE_STRTOK_R\r
+ token=strtok_r(NULL,"/",&pos);\r
+#else\r
+ token=strtok(NULL,"/");\r
+#endif\r
+ }\r
+}\r
+\r
+bool Rule::authorized(SPRequest& request, Session* session) const\r
+{\r
+ /*\r
+ TODO: port...\r
+ // Map alias in rule to the attribute.\r
+ Iterator<IAAP*> provs=st->getApplication()->getAAPProviders();\r
+ AAP wrapper(provs,m_alias.c_str());\r
+ if (wrapper.fail()) {\r
+ st->log(ShibTarget::LogLevelWarn, string("AccessControl plugin didn't recognize rule (") + m_alias + "), check AAP for corresponding Alias");\r
+ return false;\r
+ }\r
+ else if (!entry) {\r
+ st->log(ShibTarget::LogLevelWarn, "AccessControl plugin not given a valid session to evaluate, are you using lazy sessions?");\r
+ return false;\r
+ }\r
+ \r
+ // Find the corresponding attribute. This isn't very efficient...\r
+ pair<const char*,const SAMLResponse*> filtered=entry->getFilteredTokens(false,true);\r
+ Iterator<SAMLAssertion*> a_iter(filtered.second ? filtered.second->getAssertions() : EMPTY(SAMLAssertion*));\r
+ while (a_iter.hasNext()) {\r
+ SAMLAssertion* assert=a_iter.next();\r
+ Iterator<SAMLStatement*> statements=assert->getStatements();\r
+ while (statements.hasNext()) {\r
+ SAMLAttributeStatement* astate=dynamic_cast<SAMLAttributeStatement*>(statements.next());\r
+ if (!astate)\r
+ continue;\r
+ Iterator<SAMLAttribute*> attrs=astate->getAttributes();\r
+ while (attrs.hasNext()) {\r
+ SAMLAttribute* attr=attrs.next();\r
+ if (!XMLString::compareString(attr->getName(),wrapper->getName()) &&\r
+ !XMLString::compareString(attr->getNamespace(),wrapper->getNamespace())) {\r
+ // Now we have to intersect the attribute's values against the rule's list.\r
+ Iterator<string> vals=attr->getSingleByteValues();\r
+ if (!vals.hasNext())\r
+ return false;\r
+ for (vector<string>::const_iterator ival=m_vals.begin(); ival!=m_vals.end(); ival++) {\r
+ vals.reset();\r
+ while (vals.hasNext()) {\r
+ const string& v=vals.next();\r
+ if ((wrapper->getCaseSensitive() && v == *ival) || (!wrapper->getCaseSensitive() && !strcasecmp(v.c_str(),ival->c_str()))) {\r
+ st->log(ShibTarget::LogLevelDebug, string("XMLAccessControl plugin expecting " + *ival + ", authz granted"));\r
+ return true;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ */\r
+ return true;\r
+}\r
+\r
+Operator::Operator(const DOMElement* e)\r
+{\r
+ if (XMLString::equals(e->getLocalName(),NOT))\r
+ m_op=OP_NOT;\r
+ else if (XMLString::equals(e->getLocalName(),AND))\r
+ m_op=OP_AND;\r
+ else if (XMLString::equals(e->getLocalName(),OR))\r
+ m_op=OP_OR;\r
+ else\r
+ throw ConfigurationException("Unrecognized operator in access control rule");\r
+ \r
+ try {\r
+ e=XMLHelper::getFirstChildElement(e);\r
+ if (XMLString::equals(e->getLocalName(),_Rule))\r
+ m_operands.push_back(new Rule(e));\r
+ else\r
+ m_operands.push_back(new Operator(e));\r
+ \r
+ if (m_op==OP_NOT)\r
+ return;\r
+ \r
+ e=XMLHelper::getNextSiblingElement(e);\r
+ while (e) {\r
+ if (XMLString::equals(e->getLocalName(),_Rule))\r
+ m_operands.push_back(new Rule(e));\r
+ else\r
+ m_operands.push_back(new Operator(e));\r
+ e=XMLHelper::getNextSiblingElement(e);\r
+ }\r
+ }\r
+ catch (exception&) {\r
+ for_each(m_operands.begin(),m_operands.end(),xmltooling::cleanup<AccessControl>());\r
+ throw;\r
+ }\r
+}\r
+\r
+Operator::~Operator()\r
+{\r
+ for_each(m_operands.begin(),m_operands.end(),xmltooling::cleanup<AccessControl>());\r
+}\r
+\r
+bool Operator::authorized(SPRequest& request, Session* session) const\r
+{\r
+ switch (m_op) {\r
+ case OP_NOT:\r
+ return !m_operands[0]->authorized(request,session);\r
+ \r
+ case OP_AND:\r
+ {\r
+ for (vector<AccessControl*>::const_iterator i=m_operands.begin(); i!=m_operands.end(); i++) {\r
+ if (!(*i)->authorized(request,session))\r
+ return false;\r
+ }\r
+ return true;\r
+ }\r
+ \r
+ case OP_OR:\r
+ {\r
+ for (vector<AccessControl*>::const_iterator i=m_operands.begin(); i!=m_operands.end(); i++) {\r
+ if ((*i)->authorized(request,session))\r
+ return true;\r
+ }\r
+ return false;\r
+ }\r
+ }\r
+ //st->log(ShibTarget::LogLevelWarn,"Unknown operation in access control policy, denying access");\r
+ return false;\r
+}\r
+\r
+pair<bool,DOMElement*> XMLAccessControl::load()\r
+{\r
+ // Load from source using base class.\r
+ pair<bool,DOMElement*> raw = ReloadableXMLFile::load();\r
+ \r
+ // If we own it, wrap it.\r
+ XercesJanitor<DOMDocument> docjanitor(raw.first ? raw.second->getOwnerDocument() : NULL);\r
+\r
+ // Check for AccessControl wrapper and drop a level.\r
+ if (XMLString::equals(raw.second->getLocalName(),_AccessControl))\r
+ raw.second = XMLHelper::getFirstChildElement(raw.second);\r
+ \r
+ AccessControl* authz;\r
+ if (XMLString::equals(raw.second->getLocalName(),_Rule))\r
+ authz=new Rule(raw.second);\r
+ else\r
+ authz=new Operator(raw.second);\r
+\r
+ delete m_rootAuthz;\r
+ m_rootAuthz = authz;\r
+ return make_pair(false,(DOMElement*)NULL);\r
+}\r
+\r
+bool XMLAccessControl::authorized(SPRequest& request, Session* session) const\r
+{\r
+ return m_rootAuthz ? m_rootAuthz->authorized(request,session) : false;\r
+}\r
-/*
- * Copyright 2001-2005 Internet2
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* XMLRequestMapper.cpp - an XML-based map of URLs to application names and settings
-
- Scott Cantor
- 1/6/04
-
- $History:$
-*/
-
-#include "internal.h"
-
-#include <algorithm>
-#include <shibsp/DOMPropertySet.h>
-#include <xmltooling/util/ReloadableXMLFile.h>
-#include <xmltooling/util/XMLHelper.h>
-
-using namespace shibsp;
-using namespace shibtarget;
-using namespace xmltooling;
-using namespace log4cpp;
-using namespace std;
-
-namespace shibtarget {
-
- // Blocks access when an ACL plugin fails to load.
- class AccessControlDummy : public IAccessControl
- {
- public:
- Lockable* lock() {
- return this;
- }
-
- void unlock() {}
-
- bool authorized(ShibTarget* st, ISessionCacheEntry* entry) const {
- return false;
- }
- };
-
- class Override : public DOMPropertySet, public DOMNodeFilter
- {
- public:
- Override() : m_base(NULL), m_acl(NULL) {}
- Override(const DOMElement* e, Category& log, const Override* base=NULL);
- ~Override();
-
- // PropertySet
- 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;
- pair<bool,unsigned int> getUnsignedInt(const char* name, const char* ns=NULL) const;
- pair<bool,int> getInt(const char* name, const char* ns=NULL) const;
- const PropertySet* getPropertySet(const char* name, const char* ns="urn:mace:shibboleth:target:config:1.0") const;
-
- // Provides filter to exclude special config elements.
- short acceptNode(const DOMNode* node) const;
-
- const Override* locate(const char* path) const;
- IAccessControl* getAC() const { return (m_acl ? m_acl : (m_base ? m_base->getAC() : NULL)); }
-
- protected:
- void loadACL(const DOMElement* e, Category& log);
-
- map<string,Override*> m_map;
-
- private:
- const Override* m_base;
- IAccessControl* m_acl;
- };
-
- class XMLRequestMapperImpl : public Override
- {
- public:
- XMLRequestMapperImpl(const DOMElement* e, Category& log);
-
- ~XMLRequestMapperImpl() {
- if (m_document)
- m_document->release();
- }
-
- void setDocument(DOMDocument* doc) {
- m_document = doc;
- }
-
- const Override* findOverride(const char* vhost, const char* path) const;
-
- private:
- map<string,Override*> m_extras;
- DOMDocument* m_document;
- };
-
-#if defined (_MSC_VER)
- #pragma warning( push )
- #pragma warning( disable : 4250 )
-#endif
-
- class XMLRequestMapper : public IRequestMapper, public ReloadableXMLFile
- {
- public:
- XMLRequestMapper(const DOMElement* e)
- : ReloadableXMLFile(e), m_impl(NULL), m_log(Category::getInstance(SHIBT_LOGCAT".RequestMapper")) {
- load();
- }
-
- ~XMLRequestMapper() {
- delete m_impl;
- }
-
- virtual Settings getSettings(ShibTarget* st) const;
-
- protected:
- pair<bool,DOMElement*> load();
-
- private:
- XMLRequestMapperImpl* m_impl;
- Category& m_log;
- };
-
-#if defined (_MSC_VER)
- #pragma warning( pop )
-#endif
-
- static const XMLCh AccessControl[] = UNICODE_LITERAL_13(A,c,c,e,s,s,C,o,n,t,r,o,l);
- static const XMLCh AccessControlProvider[] = UNICODE_LITERAL_21(A,c,c,e,s,s,C,o,n,t,r,o,l,P,r,o,v,i,d,e,r);
- static const XMLCh htaccess[] = UNICODE_LITERAL_8(h,t,a,c,c,e,s,s);
- static const XMLCh Host[] = UNICODE_LITERAL_4(H,o,s,t);
- static const XMLCh Path[] = UNICODE_LITERAL_4(P,a,t,h);
- static const XMLCh name[] = UNICODE_LITERAL_4(n,a,m,e);
- static const XMLCh type[] = UNICODE_LITERAL_4(t,y,p,e);
-}
-
-saml::IPlugIn* XMLRequestMapFactory(const DOMElement* e)
-{
- return new XMLRequestMapper(e);
-}
-
-short Override::acceptNode(const DOMNode* node) const
-{
- if (!XMLString::equals(node->getNamespaceURI(),shibspconstants::SHIB1SPCONFIG_NS))
- return FILTER_ACCEPT;
- const XMLCh* name=node->getLocalName();
- if (XMLString::equals(name,Host) ||
- XMLString::equals(name,Path) ||
- XMLString::equals(name,AccessControl) ||
- XMLString::equals(name,htaccess) ||
- XMLString::equals(name,AccessControlProvider))
- return FILTER_REJECT;
-
- return FILTER_ACCEPT;
-}
-
-void Override::loadACL(const DOMElement* e, Category& log)
-{
- try {
- saml::IPlugIn* plugin=NULL;
- const DOMElement* acl=XMLHelper::getFirstChildElement(e,htaccess);
- if (acl) {
- log.info("building Apache htaccess provider...");
- plugin=saml::SAMLConfig::getConfig().getPlugMgr().newPlugin(HTACCESS_ACCESSCONTROL,acl);
- }
- else {
- acl=XMLHelper::getFirstChildElement(e,AccessControl);
- if (acl) {
- log.info("building XML-based Access Control provider...");
- plugin=saml::SAMLConfig::getConfig().getPlugMgr().newPlugin(XML_ACCESSCONTROL,acl);
- }
- else {
- acl=XMLHelper::getFirstChildElement(e,AccessControlProvider);
- if (acl) {
- xmltooling::auto_ptr_char type(acl->getAttributeNS(NULL,type));
- log.info("building Access Control provider of type %s...",type.get());
- plugin=saml::SAMLConfig::getConfig().getPlugMgr().newPlugin(type.get(),acl);
- }
- }
- }
- if (plugin) {
- IAccessControl* acl=dynamic_cast<IAccessControl*>(plugin);
- if (acl)
- m_acl=acl;
- else {
- delete plugin;
- throw UnknownExtensionException("plugin was not an Access Control provider");
- }
- }
- }
- catch (exception& ex) {
- log.crit("exception building AccessControl provider: %s", ex.what());
- m_acl = new AccessControlDummy();
- }
-}
-
-Override::Override(const DOMElement* e, Category& log, const Override* base) : m_base(base), m_acl(NULL)
-{
- try {
- // Load the property set.
- load(e,log,this);
-
- // Load any AccessControl provider.
- loadACL(e,log);
-
- // Handle nested Paths.
- DOMElement* path = XMLHelper::getFirstChildElement(e,Path);
- for (int i=1; path; ++i, path=XMLHelper::getNextSiblingElement(path,Path)) {
- const XMLCh* n=path->getAttributeNS(NULL,name);
-
- // Skip any leading slashes.
- while (n && *n==chForwardSlash)
- n++;
-
- // Check for empty name.
- if (!n || !*n) {
- log.warn("skipping Path element (%d) with empty name attribute", i);
- continue;
- }
-
- // Check for an embedded slash.
- int slash=XMLString::indexOf(n,chForwardSlash);
- if (slash>0) {
- // Copy the first path segment.
- XMLCh* namebuf=new XMLCh[slash + 1];
- for (int pos=0; pos < slash; pos++)
- namebuf[pos]=n[pos];
- namebuf[slash]=chNull;
-
- // Move past the slash in the original pathname.
- n=n+slash+1;
-
- // Skip any leading slashes again.
- while (*n==chForwardSlash)
- n++;
-
- if (*n) {
- // Create a placeholder Path element for the first path segment and replant under it.
- DOMElement* newpath=path->getOwnerDocument()->createElementNS(shibspconstants::SHIB1SPCONFIG_NS,Path);
- newpath->setAttributeNS(NULL,name,namebuf);
- path->setAttributeNS(NULL,name,n);
- path->getParentNode()->replaceChild(newpath,path);
- newpath->appendChild(path);
-
- // Repoint our locals at the new parent.
- path=newpath;
- n=path->getAttributeNS(NULL,name);
- }
- else {
- // All we had was a pathname with trailing slash(es), so just reset it without them.
- path->setAttributeNS(NULL,name,namebuf);
- n=path->getAttributeNS(NULL,name);
- }
- delete[] namebuf;
- }
-
- Override* o=new Override(path,log,this);
- pair<bool,const char*> name=o->getString("name");
- char* dup=strdup(name.second);
- for (char* pch=dup; *pch; pch++)
- *pch=tolower(*pch);
- if (m_map.count(dup)) {
- log.warn("Skipping duplicate Path element (%s)",dup);
- free(dup);
- delete o;
- continue;
- }
- m_map[dup]=o;
- free(dup);
- }
- }
- catch (exception&) {
- delete m_acl;
- for_each(m_map.begin(),m_map.end(),xmltooling::cleanup_pair<string,Override>());
- throw;
- }
-}
-
-Override::~Override()
-{
- delete m_acl;
- for_each(m_map.begin(),m_map.end(),xmltooling::cleanup_pair<string,Override>());
-}
-
-pair<bool,bool> Override::getBool(const char* name, const char* ns) const
-{
- pair<bool,bool> ret=DOMPropertySet::getBool(name,ns);
- if (ret.first)
- return ret;
- return m_base ? m_base->getBool(name,ns) : ret;
-}
-
-pair<bool,const char*> Override::getString(const char* name, const char* ns) const
-{
- pair<bool,const char*> ret=DOMPropertySet::getString(name,ns);
- if (ret.first)
- return ret;
- return m_base ? m_base->getString(name,ns) : ret;
-}
-
-pair<bool,const XMLCh*> Override::getXMLString(const char* name, const char* ns) const
-{
- pair<bool,const XMLCh*> ret=DOMPropertySet::getXMLString(name,ns);
- if (ret.first)
- return ret;
- return m_base ? m_base->getXMLString(name,ns) : ret;
-}
-
-pair<bool,unsigned int> Override::getUnsignedInt(const char* name, const char* ns) const
-{
- pair<bool,unsigned int> ret=DOMPropertySet::getUnsignedInt(name,ns);
- if (ret.first)
- return ret;
- return m_base ? m_base->getUnsignedInt(name,ns) : ret;
-}
-
-pair<bool,int> Override::getInt(const char* name, const char* ns) const
-{
- pair<bool,int> ret=DOMPropertySet::getInt(name,ns);
- if (ret.first)
- return ret;
- return m_base ? m_base->getInt(name,ns) : ret;
-}
-
-const PropertySet* Override::getPropertySet(const char* name, const char* ns) const
-{
- const PropertySet* ret=DOMPropertySet::getPropertySet(name,ns);
- if (ret || !m_base)
- return ret;
- return m_base->getPropertySet(name,ns);
-}
-
-const Override* Override::locate(const char* path) const
-{
- char* dup=strdup(path);
- char* sep=strchr(dup,'?');
- if (sep)
- *sep=0;
- for (char* pch=dup; *pch; pch++)
- *pch=tolower(*pch);
-
- const Override* o=this;
-
-#ifdef HAVE_STRTOK_R
- char* pos=NULL;
- const char* token=strtok_r(dup,"/",&pos);
-#else
- const char* token=strtok(dup,"/");
-#endif
- while (token)
- {
- map<string,Override*>::const_iterator i=o->m_map.find(token);
- if (i==o->m_map.end())
- break;
- o=i->second;
-#ifdef HAVE_STRTOK_R
- token=strtok_r(NULL,"/",&pos);
-#else
- token=strtok(NULL,"/");
-#endif
- }
-
- free(dup);
- return o;
-}
-
-XMLRequestMapperImpl::XMLRequestMapperImpl(const DOMElement* e, Category& log) : m_document(NULL)
-{
-#ifdef _DEBUG
- xmltooling::NDC ndc("XMLRequestMapperImpl");
-#endif
-
- // Load the property set.
- load(e,log,this);
-
- // Load any AccessControl provider.
- loadACL(e,log);
-
- // Loop over the Host elements.
- const DOMElement* host = XMLHelper::getFirstChildElement(e,Host);
- for (int i=1; host; ++i, host=XMLHelper::getNextSiblingElement(host,Host)) {
- const XMLCh* n=host->getAttributeNS(NULL,name);
- if (!n || !*n) {
- log.warn("Skipping Host element (%d) with empty name attribute",i);
- continue;
- }
-
- Override* o=new Override(host,log,this);
- pair<bool,const char*> name=o->getString("name");
- pair<bool,const char*> scheme=o->getString("scheme");
- pair<bool,const char*> port=o->getString("port");
-
- char* dup=strdup(name.second);
- for (char* pch=dup; *pch; pch++)
- *pch=tolower(*pch);
- auto_ptr<char> dupwrap(dup);
-
- if (!scheme.first && port.first) {
- // No scheme, but a port, so assume http.
- scheme = pair<bool,const char*>(true,"http");
- }
- else if (scheme.first && !port.first) {
- // Scheme, no port, so default it.
- // XXX Use getservbyname instead?
- port.first = true;
- if (!strcmp(scheme.second,"http"))
- port.second = "80";
- else if (!strcmp(scheme.second,"https"))
- port.second = "443";
- else if (!strcmp(scheme.second,"ftp"))
- port.second = "21";
- else if (!strcmp(scheme.second,"ldap"))
- port.second = "389";
- else if (!strcmp(scheme.second,"ldaps"))
- port.second = "636";
- }
-
- if (scheme.first) {
- string url(scheme.second);
- url=url + "://" + dup;
-
- // Is this the default port?
- if ((!strcmp(scheme.second,"http") && !strcmp(port.second,"80")) ||
- (!strcmp(scheme.second,"https") && !strcmp(port.second,"443")) ||
- (!strcmp(scheme.second,"ftp") && !strcmp(port.second,"21")) ||
- (!strcmp(scheme.second,"ldap") && !strcmp(port.second,"389")) ||
- (!strcmp(scheme.second,"ldaps") && !strcmp(port.second,"636"))) {
- // First store a port-less version.
- if (m_map.count(url) || m_extras.count(url)) {
- log.warn("Skipping duplicate Host element (%s)",url.c_str());
- delete o;
- continue;
- }
- m_map[url]=o;
- log.debug("Added <Host> mapping for %s",url.c_str());
-
- // Now append the port. We use the extras vector, to avoid double freeing the object later.
- url=url + ':' + port.second;
- m_extras[url]=o;
- log.debug("Added <Host> mapping for %s",url.c_str());
- }
- else {
- url=url + ':' + port.second;
- if (m_map.count(url) || m_extras.count(url)) {
- log.warn("Skipping duplicate Host element (%s)",url.c_str());
- delete o;
- continue;
- }
- m_map[url]=o;
- log.debug("Added <Host> mapping for %s",url.c_str());
- }
- }
- else {
- // No scheme or port, so we enter dual hosts on http:80 and https:443
- string url("http://");
- url = url + dup;
- if (m_map.count(url) || m_extras.count(url)) {
- log.warn("Skipping duplicate Host element (%s)",url.c_str());
- delete o;
- continue;
- }
- m_map[url]=o;
- log.debug("Added <Host> mapping for %s",url.c_str());
-
- url = url + ":80";
- if (m_map.count(url) || m_extras.count(url)) {
- log.warn("Skipping duplicate Host element (%s)",url.c_str());
- continue;
- }
- m_extras[url]=o;
- log.debug("Added <Host> mapping for %s",url.c_str());
-
- url = "https://";
- url = url + dup;
- if (m_map.count(url) || m_extras.count(url)) {
- log.warn("Skipping duplicate Host element (%s)",url.c_str());
- continue;
- }
- m_extras[url]=o;
- log.debug("Added <Host> mapping for %s",url.c_str());
-
- url = url + ":443";
- if (m_map.count(url) || m_extras.count(url)) {
- log.warn("Skipping duplicate Host element (%s)",url.c_str());
- continue;
- }
- m_extras[url]=o;
- log.debug("Added <Host> mapping for %s",url.c_str());
- }
- }
-}
-
-const Override* XMLRequestMapperImpl::findOverride(const char* vhost, const char* path) const
-{
- const Override* o=NULL;
- map<string,Override*>::const_iterator i=m_map.find(vhost);
- if (i!=m_map.end())
- o=i->second;
- else {
- i=m_extras.find(vhost);
- if (i!=m_extras.end())
- o=i->second;
- }
-
- return o ? o->locate(path) : this;
-}
-
-pair<bool,DOMElement*> XMLRequestMapper::load()
-{
- // Load from source using base class.
- pair<bool,DOMElement*> raw = ReloadableXMLFile::load();
-
- // If we own it, wrap it.
- XercesJanitor<DOMDocument> docjanitor(raw.first ? raw.second->getOwnerDocument() : NULL);
-
- XMLRequestMapperImpl* impl = new XMLRequestMapperImpl(raw.second,m_log);
-
- // If we held the document, transfer it to the impl. If we didn't, it's a no-op.
- impl->setDocument(docjanitor.release());
-
- delete m_impl;
- m_impl = impl;
-
- return make_pair(false,(DOMElement*)NULL);
-}
-
-IRequestMapper::Settings XMLRequestMapper::getSettings(ShibTarget* st) const
-{
- ostringstream vhost;
- vhost << st->getProtocol() << "://" << st->getHostname() << ':' << st->getPort();
-
- const Override* o=m_impl->findOverride(vhost.str().c_str(), st->getRequestURI());
-
- if (m_log.isDebugEnabled()) {
-#ifdef _DEBUG
- xmltooling::NDC ndc("getSettings");
-#endif
- pair<bool,const char*> ret=o->getString("applicationId");
- m_log.debug("mapped %s%s to %s", vhost.str().c_str(), st->getRequestURI() ? st->getRequestURI() : "", ret.second);
- }
-
- return Settings(o,o->getAC());
-}
+/*\r
+ * Copyright 2001-2005 Internet2\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/** XMLRequestMapper.cpp\r
+ * \r
+ * XML-based RequestMapper implementation\r
+ */\r
+\r
+#include "internal.h"\r
+#include "AccessControl.h"\r
+#include "RequestMapper.h"\r
+#include "SPRequest.h"\r
+#include "util/DOMPropertySet.h"\r
+#include "util/SPConstants.h"\r
+\r
+#include <xmltooling/util/NDC.h>\r
+#include <xmltooling/util/ReloadableXMLFile.h>\r
+#include <xmltooling/util/XMLHelper.h>\r
+#include <xercesc/util/XMLUniDefs.hpp>\r
+\r
+using namespace shibsp;\r
+using namespace xmltooling;\r
+using namespace log4cpp;\r
+using namespace std;\r
+\r
+namespace shibsp {\r
+\r
+ // Blocks access when an ACL plugin fails to load. \r
+ class AccessControlDummy : public AccessControl\r
+ {\r
+ public:\r
+ Lockable* lock() {\r
+ return this;\r
+ }\r
+ \r
+ void unlock() {}\r
+ \r
+ bool authorized(SPRequest& request, Session* session) const {\r
+ return false;\r
+ }\r
+ };\r
+\r
+ class Override : public DOMPropertySet, public DOMNodeFilter\r
+ {\r
+ public:\r
+ Override() : m_base(NULL), m_acl(NULL) {}\r
+ Override(const DOMElement* e, Category& log, const Override* base=NULL);\r
+ ~Override();\r
+\r
+ // PropertySet\r
+ pair<bool,bool> getBool(const char* name, const char* ns=NULL) const;\r
+ pair<bool,const char*> getString(const char* name, const char* ns=NULL) const;\r
+ pair<bool,const XMLCh*> getXMLString(const char* name, const char* ns=NULL) const;\r
+ pair<bool,unsigned int> getUnsignedInt(const char* name, const char* ns=NULL) const;\r
+ pair<bool,int> getInt(const char* name, const char* ns=NULL) const;\r
+ const PropertySet* getPropertySet(const char* name, const char* ns="urn:mace:shibboleth:target:config:1.0") const;\r
+ \r
+ // Provides filter to exclude special config elements.\r
+ short acceptNode(const DOMNode* node) const;\r
+\r
+ const Override* locate(const char* path) const;\r
+ AccessControl* getAC() const { return (m_acl ? m_acl : (m_base ? m_base->getAC() : NULL)); }\r
+ \r
+ protected:\r
+ void loadACL(const DOMElement* e, Category& log);\r
+ \r
+ map<string,Override*> m_map;\r
+ \r
+ private:\r
+ const Override* m_base;\r
+ AccessControl* m_acl;\r
+ };\r
+\r
+ class XMLRequestMapperImpl : public Override\r
+ {\r
+ public:\r
+ XMLRequestMapperImpl(const DOMElement* e, Category& log);\r
+\r
+ ~XMLRequestMapperImpl() {\r
+ if (m_document)\r
+ m_document->release();\r
+ }\r
+\r
+ void setDocument(DOMDocument* doc) {\r
+ m_document = doc;\r
+ }\r
+ \r
+ const Override* findOverride(const char* vhost, const char* path) const;\r
+\r
+ private: \r
+ map<string,Override*> m_extras;\r
+ DOMDocument* m_document;\r
+ };\r
+\r
+#if defined (_MSC_VER)\r
+ #pragma warning( push )\r
+ #pragma warning( disable : 4250 )\r
+#endif\r
+\r
+ class XMLRequestMapper : public RequestMapper, public ReloadableXMLFile\r
+ {\r
+ public:\r
+ XMLRequestMapper(const DOMElement* e)\r
+ : ReloadableXMLFile(e), m_impl(NULL), m_log(Category::getInstance(SHIBSP_LOGCAT".RequestMapper")) {\r
+ load();\r
+ }\r
+\r
+ ~XMLRequestMapper() {\r
+ delete m_impl;\r
+ }\r
+\r
+ Settings getSettings(const SPRequest& request) const;\r
+\r
+ protected:\r
+ pair<bool,DOMElement*> load();\r
+\r
+ private:\r
+ XMLRequestMapperImpl* m_impl;\r
+ Category& m_log;\r
+ };\r
+\r
+#if defined (_MSC_VER)\r
+ #pragma warning( pop )\r
+#endif\r
+\r
+ RequestMapper* SHIBSP_DLLLOCAL XMLRequestMapperFactory(const DOMElement* const & e)\r
+ {\r
+ return new XMLRequestMapper(e);\r
+ }\r
+\r
+ static const XMLCh _AccessControl[] = UNICODE_LITERAL_13(A,c,c,e,s,s,C,o,n,t,r,o,l);\r
+ static const XMLCh AccessControlProvider[] = UNICODE_LITERAL_21(A,c,c,e,s,s,C,o,n,t,r,o,l,P,r,o,v,i,d,e,r);\r
+ static const XMLCh htaccess[] = UNICODE_LITERAL_8(h,t,a,c,c,e,s,s);\r
+ static const XMLCh Host[] = UNICODE_LITERAL_4(H,o,s,t);\r
+ static const XMLCh Path[] = UNICODE_LITERAL_4(P,a,t,h);\r
+ static const XMLCh name[] = UNICODE_LITERAL_4(n,a,m,e);\r
+ static const XMLCh type[] = UNICODE_LITERAL_4(t,y,p,e);\r
+}\r
+\r
+void SHIBSP_API shibsp::registerRequestMappers()\r
+{\r
+ SPConfig& conf=SPConfig::getConfig();\r
+ conf.RequestMapperManager.registerFactory(XML_REQUEST_MAPPER, XMLRequestMapperFactory);\r
+ conf.RequestMapperManager.registerFactory(NATIVE_REQUEST_MAPPER, XMLRequestMapperFactory);\r
+}\r
+\r
+short Override::acceptNode(const DOMNode* node) const\r
+{\r
+ if (!XMLString::equals(node->getNamespaceURI(),shibspconstants::SHIB1SPCONFIG_NS))\r
+ return FILTER_ACCEPT;\r
+ const XMLCh* name=node->getLocalName();\r
+ if (XMLString::equals(name,Host) ||\r
+ XMLString::equals(name,Path) ||\r
+ XMLString::equals(name,_AccessControl) ||\r
+ XMLString::equals(name,htaccess) ||\r
+ XMLString::equals(name,AccessControlProvider))\r
+ return FILTER_REJECT;\r
+\r
+ return FILTER_ACCEPT;\r
+}\r
+\r
+void Override::loadACL(const DOMElement* e, Category& log)\r
+{\r
+ try {\r
+ const DOMElement* acl=XMLHelper::getFirstChildElement(e,htaccess);\r
+ if (acl) {\r
+ log.info("building Apache htaccess AccessControl provider...");\r
+ m_acl=SPConfig::getConfig().AccessControlManager.newPlugin(HT_ACCESS_CONTROL,acl);\r
+ }\r
+ else {\r
+ acl=XMLHelper::getFirstChildElement(e,_AccessControl);\r
+ if (acl) {\r
+ log.info("building XML-based AccessControl provider...");\r
+ m_acl=SPConfig::getConfig().AccessControlManager.newPlugin(XML_ACCESS_CONTROL,acl);\r
+ }\r
+ else {\r
+ acl=XMLHelper::getFirstChildElement(e,AccessControlProvider);\r
+ if (acl) {\r
+ xmltooling::auto_ptr_char type(acl->getAttributeNS(NULL,type));\r
+ log.info("building AccessControl provider of type %s...",type.get());\r
+ m_acl=SPConfig::getConfig().AccessControlManager.newPlugin(type.get(),acl);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ catch (exception& ex) {\r
+ log.crit("exception building AccessControl provider: %s", ex.what());\r
+ m_acl = new AccessControlDummy();\r
+ }\r
+}\r
+\r
+Override::Override(const DOMElement* e, Category& log, const Override* base) : m_base(base), m_acl(NULL)\r
+{\r
+ try {\r
+ // Load the property set.\r
+ load(e,log,this);\r
+ \r
+ // Load any AccessControl provider.\r
+ loadACL(e,log);\r
+ \r
+ // Handle nested Paths.\r
+ DOMElement* path = XMLHelper::getFirstChildElement(e,Path);\r
+ for (int i=1; path; ++i, path=XMLHelper::getNextSiblingElement(path,Path)) {\r
+ const XMLCh* n=path->getAttributeNS(NULL,name);\r
+ \r
+ // Skip any leading slashes.\r
+ while (n && *n==chForwardSlash)\r
+ n++;\r
+ \r
+ // Check for empty name.\r
+ if (!n || !*n) {\r
+ log.warn("skipping Path element (%d) with empty name attribute", i);\r
+ continue;\r
+ }\r
+\r
+ // Check for an embedded slash.\r
+ int slash=XMLString::indexOf(n,chForwardSlash);\r
+ if (slash>0) {\r
+ // Copy the first path segment.\r
+ XMLCh* namebuf=new XMLCh[slash + 1];\r
+ for (int pos=0; pos < slash; pos++)\r
+ namebuf[pos]=n[pos];\r
+ namebuf[slash]=chNull;\r
+ \r
+ // Move past the slash in the original pathname.\r
+ n=n+slash+1;\r
+ \r
+ // Skip any leading slashes again.\r
+ while (*n==chForwardSlash)\r
+ n++;\r
+ \r
+ if (*n) {\r
+ // Create a placeholder Path element for the first path segment and replant under it.\r
+ DOMElement* newpath=path->getOwnerDocument()->createElementNS(shibspconstants::SHIB1SPCONFIG_NS,Path);\r
+ newpath->setAttributeNS(NULL,name,namebuf);\r
+ path->setAttributeNS(NULL,name,n);\r
+ path->getParentNode()->replaceChild(newpath,path);\r
+ newpath->appendChild(path);\r
+ \r
+ // Repoint our locals at the new parent.\r
+ path=newpath;\r
+ n=path->getAttributeNS(NULL,name);\r
+ }\r
+ else {\r
+ // All we had was a pathname with trailing slash(es), so just reset it without them.\r
+ path->setAttributeNS(NULL,name,namebuf);\r
+ n=path->getAttributeNS(NULL,name);\r
+ }\r
+ delete[] namebuf;\r
+ }\r
+ \r
+ Override* o=new Override(path,log,this);\r
+ pair<bool,const char*> name=o->getString("name");\r
+ char* dup=strdup(name.second);\r
+ for (char* pch=dup; *pch; pch++)\r
+ *pch=tolower(*pch);\r
+ if (m_map.count(dup)) {\r
+ log.warn("Skipping duplicate Path element (%s)",dup);\r
+ free(dup);\r
+ delete o;\r
+ continue;\r
+ }\r
+ m_map[dup]=o;\r
+ free(dup);\r
+ }\r
+ }\r
+ catch (exception&) {\r
+ delete m_acl;\r
+ for_each(m_map.begin(),m_map.end(),xmltooling::cleanup_pair<string,Override>());\r
+ throw;\r
+ }\r
+}\r
+\r
+Override::~Override()\r
+{\r
+ delete m_acl;\r
+ for_each(m_map.begin(),m_map.end(),xmltooling::cleanup_pair<string,Override>());\r
+}\r
+\r
+pair<bool,bool> Override::getBool(const char* name, const char* ns) const\r
+{\r
+ pair<bool,bool> ret=DOMPropertySet::getBool(name,ns);\r
+ if (ret.first)\r
+ return ret;\r
+ return m_base ? m_base->getBool(name,ns) : ret;\r
+}\r
+\r
+pair<bool,const char*> Override::getString(const char* name, const char* ns) const\r
+{\r
+ pair<bool,const char*> ret=DOMPropertySet::getString(name,ns);\r
+ if (ret.first)\r
+ return ret;\r
+ return m_base ? m_base->getString(name,ns) : ret;\r
+}\r
+\r
+pair<bool,const XMLCh*> Override::getXMLString(const char* name, const char* ns) const\r
+{\r
+ pair<bool,const XMLCh*> ret=DOMPropertySet::getXMLString(name,ns);\r
+ if (ret.first)\r
+ return ret;\r
+ return m_base ? m_base->getXMLString(name,ns) : ret;\r
+}\r
+\r
+pair<bool,unsigned int> Override::getUnsignedInt(const char* name, const char* ns) const\r
+{\r
+ pair<bool,unsigned int> ret=DOMPropertySet::getUnsignedInt(name,ns);\r
+ if (ret.first)\r
+ return ret;\r
+ return m_base ? m_base->getUnsignedInt(name,ns) : ret;\r
+}\r
+\r
+pair<bool,int> Override::getInt(const char* name, const char* ns) const\r
+{\r
+ pair<bool,int> ret=DOMPropertySet::getInt(name,ns);\r
+ if (ret.first)\r
+ return ret;\r
+ return m_base ? m_base->getInt(name,ns) : ret;\r
+}\r
+\r
+const PropertySet* Override::getPropertySet(const char* name, const char* ns) const\r
+{\r
+ const PropertySet* ret=DOMPropertySet::getPropertySet(name,ns);\r
+ if (ret || !m_base)\r
+ return ret;\r
+ return m_base->getPropertySet(name,ns);\r
+}\r
+\r
+const Override* Override::locate(const char* path) const\r
+{\r
+ char* dup=strdup(path);\r
+ char* sep=strchr(dup,'?');\r
+ if (sep)\r
+ *sep=0;\r
+ for (char* pch=dup; *pch; pch++)\r
+ *pch=tolower(*pch);\r
+ \r
+ const Override* o=this;\r
+ \r
+#ifdef HAVE_STRTOK_R\r
+ char* pos=NULL;\r
+ const char* token=strtok_r(dup,"/",&pos);\r
+#else\r
+ const char* token=strtok(dup,"/");\r
+#endif\r
+ while (token)\r
+ {\r
+ map<string,Override*>::const_iterator i=o->m_map.find(token);\r
+ if (i==o->m_map.end())\r
+ break;\r
+ o=i->second;\r
+#ifdef HAVE_STRTOK_R\r
+ token=strtok_r(NULL,"/",&pos);\r
+#else\r
+ token=strtok(NULL,"/");\r
+#endif\r
+ }\r
+\r
+ free(dup);\r
+ return o;\r
+}\r
+\r
+XMLRequestMapperImpl::XMLRequestMapperImpl(const DOMElement* e, Category& log) : m_document(NULL)\r
+{\r
+#ifdef _DEBUG\r
+ xmltooling::NDC ndc("XMLRequestMapperImpl");\r
+#endif\r
+\r
+ // Load the property set.\r
+ load(e,log,this);\r
+ \r
+ // Load any AccessControl provider.\r
+ loadACL(e,log);\r
+\r
+ // Loop over the Host elements.\r
+ const DOMElement* host = XMLHelper::getFirstChildElement(e,Host);\r
+ for (int i=1; host; ++i, host=XMLHelper::getNextSiblingElement(host,Host)) {\r
+ const XMLCh* n=host->getAttributeNS(NULL,name);\r
+ if (!n || !*n) {\r
+ log.warn("Skipping Host element (%d) with empty name attribute",i);\r
+ continue;\r
+ }\r
+ \r
+ Override* o=new Override(host,log,this);\r
+ pair<bool,const char*> name=o->getString("name");\r
+ pair<bool,const char*> scheme=o->getString("scheme");\r
+ pair<bool,const char*> port=o->getString("port");\r
+ \r
+ char* dup=strdup(name.second);\r
+ for (char* pch=dup; *pch; pch++)\r
+ *pch=tolower(*pch);\r
+ auto_ptr<char> dupwrap(dup);\r
+\r
+ if (!scheme.first && port.first) {\r
+ // No scheme, but a port, so assume http.\r
+ scheme = pair<bool,const char*>(true,"http");\r
+ }\r
+ else if (scheme.first && !port.first) {\r
+ // Scheme, no port, so default it.\r
+ // XXX Use getservbyname instead?\r
+ port.first = true;\r
+ if (!strcmp(scheme.second,"http"))\r
+ port.second = "80";\r
+ else if (!strcmp(scheme.second,"https"))\r
+ port.second = "443";\r
+ else if (!strcmp(scheme.second,"ftp"))\r
+ port.second = "21";\r
+ else if (!strcmp(scheme.second,"ldap"))\r
+ port.second = "389";\r
+ else if (!strcmp(scheme.second,"ldaps"))\r
+ port.second = "636";\r
+ }\r
+\r
+ if (scheme.first) {\r
+ string url(scheme.second);\r
+ url=url + "://" + dup;\r
+ \r
+ // Is this the default port?\r
+ if ((!strcmp(scheme.second,"http") && !strcmp(port.second,"80")) ||\r
+ (!strcmp(scheme.second,"https") && !strcmp(port.second,"443")) ||\r
+ (!strcmp(scheme.second,"ftp") && !strcmp(port.second,"21")) ||\r
+ (!strcmp(scheme.second,"ldap") && !strcmp(port.second,"389")) ||\r
+ (!strcmp(scheme.second,"ldaps") && !strcmp(port.second,"636"))) {\r
+ // First store a port-less version.\r
+ if (m_map.count(url) || m_extras.count(url)) {\r
+ log.warn("Skipping duplicate Host element (%s)",url.c_str());\r
+ delete o;\r
+ continue;\r
+ }\r
+ m_map[url]=o;\r
+ log.debug("Added <Host> mapping for %s",url.c_str());\r
+ \r
+ // Now append the port. We use the extras vector, to avoid double freeing the object later.\r
+ url=url + ':' + port.second;\r
+ m_extras[url]=o;\r
+ log.debug("Added <Host> mapping for %s",url.c_str());\r
+ }\r
+ else {\r
+ url=url + ':' + port.second;\r
+ if (m_map.count(url) || m_extras.count(url)) {\r
+ log.warn("Skipping duplicate Host element (%s)",url.c_str());\r
+ delete o;\r
+ continue;\r
+ }\r
+ m_map[url]=o;\r
+ log.debug("Added <Host> mapping for %s",url.c_str());\r
+ }\r
+ }\r
+ else {\r
+ // No scheme or port, so we enter dual hosts on http:80 and https:443\r
+ string url("http://");\r
+ url = url + dup;\r
+ if (m_map.count(url) || m_extras.count(url)) {\r
+ log.warn("Skipping duplicate Host element (%s)",url.c_str());\r
+ delete o;\r
+ continue;\r
+ }\r
+ m_map[url]=o;\r
+ log.debug("Added <Host> mapping for %s",url.c_str());\r
+ \r
+ url = url + ":80";\r
+ if (m_map.count(url) || m_extras.count(url)) {\r
+ log.warn("Skipping duplicate Host element (%s)",url.c_str());\r
+ continue;\r
+ }\r
+ m_extras[url]=o;\r
+ log.debug("Added <Host> mapping for %s",url.c_str());\r
+ \r
+ url = "https://";\r
+ url = url + dup;\r
+ if (m_map.count(url) || m_extras.count(url)) {\r
+ log.warn("Skipping duplicate Host element (%s)",url.c_str());\r
+ continue;\r
+ }\r
+ m_extras[url]=o;\r
+ log.debug("Added <Host> mapping for %s",url.c_str());\r
+ \r
+ url = url + ":443";\r
+ if (m_map.count(url) || m_extras.count(url)) {\r
+ log.warn("Skipping duplicate Host element (%s)",url.c_str());\r
+ continue;\r
+ }\r
+ m_extras[url]=o;\r
+ log.debug("Added <Host> mapping for %s",url.c_str());\r
+ }\r
+ }\r
+}\r
+\r
+const Override* XMLRequestMapperImpl::findOverride(const char* vhost, const char* path) const\r
+{\r
+ const Override* o=NULL;\r
+ map<string,Override*>::const_iterator i=m_map.find(vhost);\r
+ if (i!=m_map.end())\r
+ o=i->second;\r
+ else {\r
+ i=m_extras.find(vhost);\r
+ if (i!=m_extras.end())\r
+ o=i->second;\r
+ }\r
+ \r
+ return o ? o->locate(path) : this;\r
+}\r
+\r
+pair<bool,DOMElement*> XMLRequestMapper::load()\r
+{\r
+ // Load from source using base class.\r
+ pair<bool,DOMElement*> raw = ReloadableXMLFile::load();\r
+ \r
+ // If we own it, wrap it.\r
+ XercesJanitor<DOMDocument> docjanitor(raw.first ? raw.second->getOwnerDocument() : NULL);\r
+\r
+ XMLRequestMapperImpl* impl = new XMLRequestMapperImpl(raw.second,m_log);\r
+ \r
+ // If we held the document, transfer it to the impl. If we didn't, it's a no-op.\r
+ impl->setDocument(docjanitor.release());\r
+\r
+ delete m_impl;\r
+ m_impl = impl;\r
+\r
+ return make_pair(false,(DOMElement*)NULL);\r
+}\r
+\r
+RequestMapper::Settings XMLRequestMapper::getSettings(const SPRequest& request) const\r
+{\r
+ ostringstream vhost;\r
+ vhost << request.getScheme() << "://" << request.getHostname() << ':' << request.getPort();\r
+\r
+ const Override* o=m_impl->findOverride(vhost.str().c_str(), request.getRequestURI());\r
+\r
+ if (m_log.isDebugEnabled()) {\r
+#ifdef _DEBUG\r
+ xmltooling::NDC ndc("getSettings");\r
+#endif\r
+ pair<bool,const char*> ret=o->getString("applicationId");\r
+ m_log.debug("mapped %s%s to %s", vhost.str().c_str(), request.getRequestURI() ? request.getRequestURI() : "", ret.second);\r
+ }\r
+\r
+ return Settings(o,o->getAC());\r
+}\r
*/
/**
- * @file shibsp/MetadataExt.h
+ * @file shibsp/metadata/MetadataExt.h
*
* XMLObjects representing Shibboleth metadata extensions
*/
#ifndef __shibsp_metaext_h__
#define __shibsp_metaext_h__
-#include <shibsp/SPConstants.h>
+#include <shibsp/util/SPConstants.h>
#include <xmltooling/XMLObjectBuilder.h>
#include <xmltooling/signature/KeyInfo.h>
#include <xercesc/util/XMLUniDefs.hpp>
#include "internal.h"
#include "exceptions.h"
-#include "MetadataExt.h"
+#include "metadata/MetadataExt.h"
#include <xmltooling/AbstractComplexElement.h>
#include <xmltooling/AbstractSimpleElement.h>
#include "internal.h"
#include "exceptions.h"
-#include "MetadataExt.h"
+#include "metadata/MetadataExt.h"
#include <xmltooling/validation/ValidatorSuite.h>
*/
/**
- * @file shibsp/ListenerService.h
+ * @file shibsp/remoting/ListenerService.h
*
* Interprocess remoting engine.
*/
#ifndef __shibsp_listener_h__
#define __shibsp_listener_h__
-#include <shibsp/ddf.h>
+#include <shibsp/remoting/ddf.h>
#include <map>
namespace shibsp {
*/
/**
- * @file shibsp/ddf.h
+ * @file shibsp/remoting/ddf.h
*
* C++ DDF abstraction for interpretive RPC
*/
#include "internal.h"
#include "exceptions.h"
-#include "ListenerService.h"
+#include "remoting/ListenerService.h"
#include <log4cpp/Category.hh>
#include <xercesc/dom/DOM.hpp>
#include "internal.h"
#include "exceptions.h"
-#include "SocketListener.h"
+#include "remoting/impl/SocketListener.h"
#include <errno.h>
#include <stack>
*/
/**
- * @file shibsp/SocketListener.h
+ * SocketListener.h
*
* Berkeley Socket-based ListenerService implementation
*/
# define FD_SETSIZE 1024
#endif
-#include <shibsp/ListenerService.h>
+#include <shibsp/remoting/ListenerService.h>
#include <log4cpp/Category.hh>
#include <xercesc/dom/DOM.hpp>
*/
#include "internal.h"
-#include "SocketListener.h"
+#include "remoting/impl/SocketListener.h"
#include <xercesc/util/XMLUniDefs.hpp>
#include <xmltooling/unicode.h>
*/\r
\r
#include "internal.h"\r
-#include "SocketListener.h"\r
+#include "remoting/impl/SocketListener.h"\r
\r
#include <xercesc/util/XMLUniDefs.hpp>\r
#include <xmltooling/unicode.h>\r
*/
#include "internal.h"
+#include "remoting/ddf.h"
#ifdef WIN32
# define snprintf _snprintf
#endif
-#include <shibsp/ddf.h>
-
#include <stdexcept>
#include <xercesc/dom/DOM.hpp>
#include <xercesc/util/XMLUniDefs.hpp>
*/
#include "internal.h"
-#include "MetadataExt.h"
-#include "PKIXTrustEngine.h"
+#include "metadata/MetadataExt.h"
+#include "security/PKIXTrustEngine.h"
#include <saml/saml2/metadata/Metadata.h>
#include <xmltooling/XMLToolingConfig.h>
*/
/**
- * @file shibsp/PKIXTrustEngine.h
+ * @file shibsp/security/PKIXTrustEngine.h
*
* Shibboleth-specific PKIX-validation TrustEngine
*/
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
>\r
<File\r
- RelativePath=".\ddf.cpp"\r
+ RelativePath=".\AbstractSPRequest.cpp"\r
>\r
</File>\r
<File\r
- RelativePath=".\DOMPropertySet.cpp"\r
+ RelativePath=".\Application.cpp"\r
>\r
</File>\r
<File\r
- RelativePath=".\ListenerService.cpp"\r
+ RelativePath=".\ServiceProvider.cpp"\r
>\r
</File>\r
<File\r
- RelativePath=".\MetadataExtImpl.cpp"\r
+ RelativePath=".\SPConfig.cpp"\r
>\r
</File>\r
- <File\r
- RelativePath=".\MetadataExtSchemaValidators.cpp"\r
+ <Filter\r
+ Name="util"\r
>\r
- </File>\r
- <File\r
- RelativePath=".\PKIXTrustEngine.cpp"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\ServiceProvider.cpp"\r
+ <File\r
+ RelativePath=".\util\CGIParser.cpp"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\util\DOMPropertySet.cpp"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\util\SPConstants.cpp"\r
+ >\r
+ </File>\r
+ </Filter>\r
+ <Filter\r
+ Name="security"\r
>\r
- </File>\r
- <File\r
- RelativePath=".\SocketListener.cpp"\r
+ <File\r
+ RelativePath=".\security\PKIXTrustEngine.cpp"\r
+ >\r
+ </File>\r
+ </Filter>\r
+ <Filter\r
+ Name="metadata"\r
>\r
- </File>\r
- <File\r
- RelativePath=".\SPConfig.cpp"\r
+ <File\r
+ RelativePath=".\metadata\MetadataExtImpl.cpp"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\metadata\MetadataExtSchemaValidators.cpp"\r
+ >\r
+ </File>\r
+ </Filter>\r
+ <Filter\r
+ Name="remoting"\r
>\r
- </File>\r
- <File\r
- RelativePath=".\SPConstants.cpp"\r
+ <Filter\r
+ Name="impl"\r
+ >\r
+ <File\r
+ RelativePath=".\remoting\impl\ddf.cpp"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\remoting\impl\ListenerService.cpp"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\remoting\impl\SocketListener.cpp"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\remoting\impl\SocketListener.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\remoting\impl\TCPListener.cpp"\r
+ >\r
+ </File>\r
+ </Filter>\r
+ </Filter>\r
+ <Filter\r
+ Name="impl"\r
>\r
- </File>\r
+ <File\r
+ RelativePath=".\impl\XMLAccessControl.cpp"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\impl\XMLRequestMapper.cpp"\r
+ >\r
+ </File>\r
+ </Filter>\r
</Filter>\r
<Filter\r
Name="Header Files"\r
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
>\r
<File\r
- RelativePath=".\base.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\ddf.h"\r
+ RelativePath=".\AbstractSPRequest.h"\r
>\r
</File>\r
<File\r
- RelativePath=".\DOMPropertySet.h"\r
+ RelativePath=".\AccessControl.h"\r
>\r
</File>\r
<File\r
- RelativePath=".\exceptions.h"\r
+ RelativePath=".\Application.h"\r
>\r
</File>\r
<File\r
- RelativePath=".\internal.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\ListenerService.h"\r
+ RelativePath=".\base.h"\r
>\r
</File>\r
<File\r
- RelativePath=".\MetadataExt.h"\r
+ RelativePath=".\exceptions.h"\r
>\r
</File>\r
<File\r
- RelativePath=".\PKIXTrustEngine.h"\r
+ RelativePath=".\internal.h"\r
>\r
</File>\r
<File\r
- RelativePath=".\PropertySet.h"\r
+ RelativePath=".\RequestMapper.h"\r
>\r
</File>\r
<File\r
>\r
</File>\r
<File\r
- RelativePath=".\SocketListener.h"\r
+ RelativePath=".\SessionCache.h"\r
>\r
</File>\r
<File\r
>\r
</File>\r
<File\r
- RelativePath=".\SPConstants.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\TCPListener.cpp"\r
+ RelativePath=".\SPRequest.h"\r
>\r
</File>\r
<File\r
RelativePath=".\version.h"\r
>\r
</File>\r
+ <Filter\r
+ Name="util"\r
+ >\r
+ <File\r
+ RelativePath=".\util\CGIParser.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\util\DOMPropertySet.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\util\PropertySet.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\util\SPConstants.h"\r
+ >\r
+ </File>\r
+ </Filter>\r
+ <Filter\r
+ Name="security"\r
+ >\r
+ <File\r
+ RelativePath=".\security\PKIXTrustEngine.h"\r
+ >\r
+ </File>\r
+ </Filter>\r
+ <Filter\r
+ Name="metadata"\r
+ >\r
+ <File\r
+ RelativePath=".\metadata\MetadataExt.h"\r
+ >\r
+ </File>\r
+ </Filter>\r
+ <Filter\r
+ Name="remoting"\r
+ >\r
+ <File\r
+ RelativePath=".\remoting\ddf.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\remoting\ListenerService.h"\r
+ >\r
+ </File>\r
+ </Filter>\r
</Filter>\r
<Filter\r
Name="Resource Files"\r
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * CGIParser.cpp
+ *
+ * CGI GET/POST parameter parsing
+ */
+
+#include "internal.h"
+#include "util/CGIParser.h"
+
+#include <saml/SAMLConfig.h>
+#include <saml/binding/URLEncoder.h>
+
+using namespace shibsp;
+using namespace opensaml;
+using namespace std;
+
+
+CGIParser::CGIParser(const SPRequest& request)
+{
+ const char* pch=NULL;
+ if (!strcmp(request.getMethod(),"POST"))
+ pch=request.getRequestBody();
+ else
+ pch=request.getQueryString();
+ size_t cl=pch ? strlen(pch) : 0;
+
+
+ while (cl && pch) {
+ char *name;
+ char *value;
+ value=fmakeword('&',&cl,&pch);
+ plustospace(value);
+ SAMLConfig::getConfig().getURLEncoder()->decode(value);
+ name=makeword(value,'=');
+ kvp_map.insert(pair<string,char*>(name,value));
+ free(name);
+ }
+}
+
+CGIParser::~CGIParser()
+{
+ for (multimap<string,char*>::iterator i=kvp_map.begin(); i!=kvp_map.end(); i++)
+ free(i->second);
+}
+
+pair<CGIParser::walker,CGIParser::walker> CGIParser::getParameters(const char* name) const
+{
+ return kvp_map.equal_range(name);
+}
+
+/* Parsing routines modified from NCSA source. */
+char* CGIParser::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* CGIParser::fmakeword(char stop, size_t *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;
+ }
+}
+
+void CGIParser::plustospace(char *str)
+{
+ register int x;
+
+ for(x=0;str[x];x++)
+ if(str[x] == '+') str[x] = ' ';
+}
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file shibsp/util/CGIParser.h
+ *
+ * CGI GET/POST parameter parsing
+ */
+
+#ifndef __shibsp_cgi_h__
+#define __shibsp_cgi_h__
+
+#include <shibsp/SPRequest.h>
+
+namespace shibsp {
+
+ /**
+ * CGI GET/POST parameter parsing
+ */
+ class SHIBSP_API CGIParser
+ {
+ MAKE_NONCOPYABLE(CGIParser);
+ public:
+ /**
+ * Constructor
+ *
+ * @param request SP request
+ */
+ CGIParser(const SPRequest& request);
+
+ ~CGIParser();
+
+ typedef std::multimap<std::string,char*>::const_iterator walker;
+
+ /**
+ * Returns a pair of bounded iterators around the values of a parameter.
+ *
+ * @param name name of parameter
+ * @return a pair of multimap iterators surrounding the matching value(s)
+ */
+ std::pair<walker,walker> getParameters(const char* name) const;
+
+ private:
+ char* fmakeword(char stop, unsigned int *cl, const char** ppch);
+ char* makeword(char *line, char stop);
+ void plustospace(char *str);
+
+ std::multimap<std::string,char*> kvp_map;
+ };
+};
+
+#endif /* __shibsp_cgi_h__ */
*/
#include "internal.h"
-#include "DOMPropertySet.h"
+#include "util/DOMPropertySet.h"
#include <algorithm>
#include <xmltooling/util/NDC.h>
*/
/**
- * @file shibsp/DOMPropertySet.h
+ * @file shibsp/util/DOMPropertySet.h
*
* DOM-based property set implementation.
*/
#ifndef __shibsp_dompropset_h__
#define __shibsp_dompropset_h__
-#include <shibsp/PropertySet.h>
+#include <shibsp/util/PropertySet.h>
#include <log4cpp/Category.hh>
namespace shibsp {
*/
/**
- * @file shibsp/PropertySet.h
+ * @file shibsp/util/PropertySet.h
*
* Interface to a generic set of typed properties or a DOM container of additional data.
*/
*/\r
\r
#include "internal.h"\r
-#include "SPConstants.h"\r
+#include "util/SPConstants.h"\r
#include <xercesc/util/XMLUniDefs.hpp>\r
\r
using namespace shibspconstants;\r
*/
/**
- * @file shibsp/SPConstants.h
+ * @file shibsp/util/SPConstants.h
*
* Shibboleth SP XML constants.
*/
IConfig* ini=ShibTargetConfig::getConfig().getINI();
xmltooling::Locker locker(ini);
- const IApplication* app=ini->getApplication(a_param);
+ const IApplication* app=dynamic_cast<const IApplication*>(ini->getApplication(a_param));
if (!app) {
throw ConfigurationException("Unable to locate application for new session, deleted?");
}
#include <shib-target/shib-target.h>
#include <shibsp/SPConfig.h>
-#include <shibsp/SPConstants.h>
+#include <shibsp/util/SPConstants.h>
using namespace shibsp;
using namespace shibtarget;
xmltooling::Locker locker(ini);
try {
- const IApplication* app=ini->getApplication(a_param);
+ const IApplication* app=dynamic_cast<const IApplication*>(ini->getApplication(a_param));
if (!app)
throw SAMLException("specified <Application> section not found in configuration");
xmlproviders_la_SOURCES = \
TargetedID.cpp \
XMLAAP.cpp \
- XMLAccessControl.cpp \
XMLProviders.cpp
#include "internal.h"
#include <algorithm>
#include <log4cpp/Category.hh>
-#include <shibsp/MetadataExt.h>
-#include <shibsp/SPConstants.h>
+#include <shibsp/metadata/MetadataExt.h>
+#include <shibsp/util/SPConstants.h>
#include <xmltooling/util/ReloadableXMLFile.h>
#include <xmltooling/util/XMLHelper.h>
class XMLAAP : public IAAP, public ReloadableXMLFile
{
public:
- XMLAAP(const DOMElement* e) : ReloadableXMLFile(e), m_impl(NULL) {}
+ XMLAAP(const DOMElement* e) : ReloadableXMLFile(e), m_impl(NULL) {
+ load();
+ }
~XMLAAP() {
delete m_impl;
}
PlugManager::Factory TargetedIDFactory;
PlugManager::Factory XMLAAPFactory;
-PlugManager::Factory XMLAccessControlFactory;
extern "C" int XML_EXPORTS saml_extension_init(void*)
{
conf.getPlugMgr().regFactory("edu.internet2.middleware.shibboleth.common.provider.TargetedIDFactory",&TargetedIDFactory);
conf.getPlugMgr().regFactory("edu.internet2.middleware.shibboleth.aap.provider.XMLAAP",&XMLAAPFactory);
conf.getPlugMgr().regFactory("edu.internet2.middleware.shibboleth.target.provider.XMLAAP",&XMLAAPFactory);
- conf.getPlugMgr().regFactory(XML_ACCESSCONTROL,&XMLAccessControlFactory);
return 0;
}
conf.getPlugMgr().unregFactory("edu.internet2.middleware.shibboleth.common.provider.TargetedIDFactory");
conf.getPlugMgr().unregFactory("edu.internet2.middleware.shibboleth.aap.provider.XMLAAP");
conf.getPlugMgr().unregFactory("edu.internet2.middleware.shibboleth.target.provider.XMLAAP");
- conf.getPlugMgr().unregFactory(XML_ACCESSCONTROL);
}
>
</File>
<File
- RelativePath=".\XMLAccessControl.cpp"
- >
- </File>
- <File
RelativePath="XMLProviders.cpp"
>
</File>