# include <unistd.h>
#endif
+#include <ctime>
#include <sstream>
#include <fstream>
#include <stdexcept>
-#include <shib/shib-threads.h>
+#include <saml/SAMLConfig.h>
+#include <saml/binding/URLEncoder.h>
#include <xercesc/util/Base64.hpp>
+#include <xmltooling/util/NDC.h>
+#include <xmltooling/util/TemplateEngine.h>
+#include <xmltooling/util/XMLHelper.h>
#ifndef HAVE_STRCASECMP
# define strcasecmp stricmp
#endif
-using namespace std;
-using namespace saml;
-using namespace shibboleth;
+using namespace shibsp;
using namespace shibtarget;
+using namespace shibboleth;
+using namespace saml;
+using namespace opensaml::saml2md;
using namespace log4cpp;
+using namespace std;
+
+using xmltooling::TemplateEngine;
+using xmltooling::XMLToolingException;
+using xmltooling::XMLToolingConfig;
+using xmltooling::XMLHelper;
namespace shibtarget {
class CgiParse
multimap<string,char*> kvp_map;
};
+ class ExtTemplateParameters : public TemplateEngine::TemplateParameters
+ {
+ const PropertySet* m_props;
+ public:
+ ExtTemplateParameters() : m_props(NULL) {}
+ ~ExtTemplateParameters() {}
+
+ void setPropertySet(const PropertySet* props) {
+ m_props = props;
+
+ // Create a timestamp.
+ time_t now = time(NULL);
+#ifdef HAVE_CTIME_R
+ char timebuf[32];
+ m_map["now"] = ctime_r(&now,timebuf);
+#else
+ m_map["now"] = ctime(&now);
+#endif
+ }
+
+ const char* getParameter(const char* name) const {
+ const char* pch = TemplateParameters::getParameter(name);
+ if (pch || !m_props)
+ return pch;
+ pair<bool,const char*> p = m_props->getString(name);
+ return p.first ? p.second : NULL;
+ }
+ };
+
class ShibTargetPriv
{
public:
// 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, ShibMLP &mlp);
+ void* sendError(ShibTarget* st, const char* page, ExtTemplateParameters& tp, const XMLToolingException* ex=NULL);
void clearHeaders(ShibTarget* st);
private:
)
{
#ifdef _DEBUG
- saml::NDC ndc("init");
+ xmltooling::NDC ndc("init");
#endif
if (m_priv->m_app)
- throw SAMLException("Request initialization occurred twice!");
+ throw XMLToolingException("Request initialization occurred twice!");
if (method) m_method = method;
if (protocol) m_protocol = protocol;
pair<bool,void*> ShibTarget::doCheckAuthN(bool handler)
{
#ifdef _DEBUG
- saml::NDC ndc("doCheckAuthN");
+ xmltooling::NDC ndc("doCheckAuthN");
#endif
const char* procState = "Request Processing Error";
const char* targetURL = m_url.c_str();
- ShibMLP mlp;
+ ExtTemplateParameters tp;
try {
if (!m_priv->m_app)
return make_pair(true, sendRedirect(redirectURL));
}
else {
- mlp.insert("requestURL", m_url.substr(0,m_url.find('?')));
- return make_pair(true,m_priv->sendError(this,"ssl", mlp));
+ tp.m_map["requestURL"] = m_url.substr(0,m_url.find('?'));
+ return make_pair(true,m_priv->sendError(this,"ssl", tp));
}
}
}
if (handler)
return doHandler();
else
- return pair<bool,void*>(true, returnOK());
+ return make_pair(true, returnOK());
}
// Three settings dictate how to proceed.
#else
(!authType.first || _stricmp(authType.second,"shibboleth")))
#endif
- return pair<bool,void*>(true,returnDecline());
+ return make_pair(true,returnDecline());
// Fix for secadv 20050901
m_priv->clearHeaders(this);
if (!session_id || !*session_id) {
// No session. Maybe that's acceptable?
if ((!requireSession.first || !requireSession.second) && !requireSessionWith.first)
- return pair<bool,void*>(true,returnOK());
+ return make_pair(true,returnOK());
// No cookie, but we require a session. Initiate a new session using the indicated method.
procState = "Session Initiator Error";
if (!initiator)
throw ConfigurationException(
"No session initiator found with id ($1), check requireSessionWith command.",
- params(1,requireSessionWith.second)
+ xmltooling::params(1,requireSessionWith.second)
);
}
else {
);
// Make a localized exception throw if the session isn't valid.
if (!m_priv->m_cacheEntry)
- throw InvalidSessionException("Session no longer valid.");
+ throw RetryableProfileException("Session no longer valid.");
}
- catch (SAMLException& e) {
+ catch (exception& e) {
log(LogLevelError, string("session processing failed: ") + e.what());
// If no session is required, bail now.
// to fail when it can't locate anything to process the
// AuthType. No session plus requireSession false means
// do not authenticate the user at this time.
- return pair<bool,void*>(true, returnOK());
+ return make_pair(true, returnOK());
// Try and cast down.
- SAMLException* base = &e;
+ exception* base = &e;
RetryableProfileException* trycast=dynamic_cast<RetryableProfileException*>(base);
if (trycast) {
// Session is invalid but we can retry -- initiate a new session.
if (!initiator)
throw ConfigurationException(
"No session initiator found with id ($1), check requireSessionWith command.",
- params(1,requireSessionWith.second)
+ xmltooling::params(1,requireSessionWith.second)
);
}
else {
// We're done. Everything is okay. Nothing to report. Nothing to do..
// Let the caller decide how to proceed.
log(LogLevelDebug, "doCheckAuthN succeeded");
- return pair<bool,void*>(false,NULL);
+ return make_pair(false,(void*)NULL);
}
- catch (SAMLException& e) {
- mlp.insert(e);
+ catch (XMLToolingException& e) {
+ tp.m_map["errorType"] = procState;
+ tp.m_map["errorText"] = e.what();
+ if (targetURL)
+ tp.m_map["requestURL"] = m_url.substr(0,m_url.find('?'));
+ return make_pair(true,m_priv->sendError(this, "session", tp, &e));
}
#ifndef _DEBUG
catch (...) {
- mlp.insert("errorText", "Caught an unknown exception.");
+ tp.m_map["errorType"] = procState;
+ tp.m_map["errorText"] = "Caught an unknown exception.";
+ if (targetURL)
+ tp.m_map["requestURL"] = m_url.substr(0,m_url.find('?'));
+ return make_pair(true,m_priv->sendError(this, "session", tp));
}
#endif
-
- // If we get here then we've got an error.
- mlp.insert("errorType", procState);
- if (targetURL)
- mlp.insert("requestURL", m_url.substr(0,m_url.find('?')));
-
- return pair<bool,void*>(true,m_priv->sendError(this,"session", mlp));
}
pair<bool,void*> ShibTarget::doHandler(void)
{
#ifdef _DEBUG
- saml::NDC ndc("doHandler");
+ xmltooling::NDC ndc("doHandler");
#endif
+ ExtTemplateParameters tp;
const char* procState = "Shibboleth Handler Error";
const char* targetURL = m_url.c_str();
- ShibMLP mlp;
try {
if (!m_priv->m_app)
// Make sure we only process handler requests.
if (!strstr(targetURL,handlerURL))
- return pair<bool,void*>(true, returnDecline());
+ return make_pair(true, returnDecline());
- const IPropertySet* sessionProps=m_priv->m_app->getPropertySet("Sessions");
+ const PropertySet* sessionProps=m_priv->m_app->getPropertySet("Sessions");
if (!sessionProps)
throw ConfigurationException("Unable to map request to application session settings, check configuration.");
// Make sure this is SSL, if it should be
if ((!handlerSSL.first || handlerSSL.second) && m_protocol != "https")
- throw FatalProfileException("Blocked non-SSL access to Shibboleth handler.");
+ throw opensaml::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).
const IHandler* handler=m_priv->m_app->getHandler(targetURL + strlen(handlerURL));
if (!handler)
- throw SAMLException("Shibboleth handler invoked at an unconfigured location.");
+ throw opensaml::BindingException("Shibboleth handler invoked at an unconfigured location.");
- if (saml::XML::isElementNamed(handler->getProperties()->getElement(),shibtarget::XML::SAML2META_NS,SHIBT_L(AssertionConsumerService)))
+ if (XMLHelper::isNodeNamed(handler->getProperties()->getElement(),samlconstants::SAML20MD_NS,SHIBT_L(AssertionConsumerService)))
procState = "Session Creation Error";
- else if (saml::XML::isElementNamed(handler->getProperties()->getElement(),shibtarget::XML::SHIBTARGET_NS,SHIBT_L(SessionInitiator)))
+ else if (XMLHelper::isNodeNamed(handler->getProperties()->getElement(),shibtarget::XML::SHIBTARGET_NS,SHIBT_L(SessionInitiator)))
procState = "Session Initiator Error";
- else if (saml::XML::isElementNamed(handler->getProperties()->getElement(),shibtarget::XML::SAML2META_NS,SHIBT_L(SingleLogoutService)))
+ else if (XMLHelper::isNodeNamed(handler->getProperties()->getElement(),samlconstants::SAML20MD_NS,SHIBT_L(SingleLogoutService)))
procState = "Session Termination Error";
- else if (saml::XML::isElementNamed(handler->getProperties()->getElement(),shibtarget::XML::SHIBTARGET_NS,SHIBT_L(DiagnosticService)))
+ else if (XMLHelper::isNodeNamed(handler->getProperties()->getElement(),shibtarget::XML::SHIBTARGET_NS,SHIBT_L(DiagnosticService)))
procState = "Diagnostics Error";
else
procState = "Extension Service Error";
if (hret.first)
return hret;
- throw SAMLException("Configured Shibboleth handler failed to process the request.");
+ throw opensaml::BindingException("Configured Shibboleth handler failed to process the request.");
}
catch (MetadataException& e) {
- mlp.insert(e);
+ tp.m_map["errorText"] = e.what();
// See if a metadata error page is installed.
- const IPropertySet* props=m_priv->m_app->getPropertySet("Errors");
+ const PropertySet* props=m_priv->m_app->getPropertySet("Errors");
if (props) {
pair<bool,const char*> p=props->getString("metadata");
if (p.first) {
- mlp.insert("errorType", procState);
+ tp.m_map["errorType"] = procState;
if (targetURL)
- mlp.insert("requestURL", targetURL);
- return make_pair(true,m_priv->sendError(this,"metadata", mlp));
+ tp.m_map["requestURL"] = targetURL;
+ return make_pair(true,m_priv->sendError(this, "metadata", tp));
}
}
+ throw;
}
- catch (SAMLException& e) {
- mlp.insert(e);
+ catch (XMLToolingException& e) {
+ tp.m_map["errorType"] = procState;
+ tp.m_map["errorText"] = e.what();
+ if (targetURL)
+ tp.m_map["requestURL"] = m_url.substr(0,m_url.find('?'));
+ return make_pair(true,m_priv->sendError(this, "session", tp, &e));
}
#ifndef _DEBUG
catch (...) {
- mlp.insert("errorText", "Caught an unknown exception.");
+ tp.m_map["errorType"] = procState;
+ tp.m_map["errorText"] = "Caught an unknown exception.";
+ if (targetURL)
+ tp.m_map["requestURL"] = m_url.substr(0,m_url.find('?'));
+ return make_pair(true,m_priv->sendError(this, "session", tp));
}
#endif
-
- // If we get here then we've got an error.
- mlp.insert("errorType", procState);
-
- if (targetURL)
- mlp.insert("requestURL", m_url.substr(0,m_url.find('?')));
-
- return make_pair(true,m_priv->sendError(this,"session", mlp));
}
pair<bool,void*> ShibTarget::doCheckAuthZ(void)
{
#ifdef _DEBUG
- saml::NDC ndc("doCheckAuthZ");
+ xmltooling::NDC ndc("doCheckAuthZ");
#endif
- ShibMLP mlp;
+ ExtTemplateParameters tp;
const char* procState = "Authorization Processing Error";
const char* targetURL = m_url.c_str();
#else
(!authType.first || _stricmp(authType.second,"shibboleth")))
#endif
- return pair<bool,void*>(true,returnDecline());
+ return make_pair(true,returnDecline());
// Do we have an access control plugin?
if (m_priv->m_settings.second) {
);
}
}
- catch (SAMLException&) {
+ catch (exception&) {
log(LogLevelError, "doCheckAuthZ: unable to obtain session information to pass to access control provider");
}
}
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 pair<bool,void*>(false,NULL);
+ return make_pair(false,(void*)NULL);
}
else {
log(LogLevelWarn, "doCheckAuthZ: access control provider denied access");
if (targetURL)
- mlp.insert("requestURL", targetURL);
- return make_pair(true,m_priv->sendError(this, "access", mlp));
+ tp.m_map["requestURL"] = targetURL;
+ return make_pair(true,m_priv->sendError(this, "access", tp));
}
}
else
return make_pair(true,returnDecline());
}
- catch (SAMLException& e) {
- mlp.insert(e);
+ catch (exception& e) {
+ tp.m_map["errorType"] = procState;
+ tp.m_map["errorText"] = e.what();
+ if (targetURL)
+ tp.m_map["requestURL"] = m_url.substr(0,m_url.find('?'));
+ return make_pair(true,m_priv->sendError(this, "access", tp));
}
#ifndef _DEBUG
catch (...) {
- mlp.insert("errorText", "Caught an unknown exception.");
+ tp.m_map["errorType"] = procState;
+ tp.m_map["errorText"] = "Caught an unknown exception.";
+ if (targetURL)
+ tp.m_map["requestURL"] = m_url.substr(0,m_url.find('?'));
+ return make_pair(true,m_priv->sendError(this, "access", tp));
}
#endif
-
- // If we get here then we've got an error.
- mlp.insert("errorType", procState);
-
- if (targetURL)
- mlp.insert("requestURL", m_url.substr(0,m_url.find('?')));
-
- return make_pair(true,m_priv->sendError(this, "access", mlp));
}
pair<bool,void*> ShibTarget::doExportAssertions(bool requireSession)
{
#ifdef _DEBUG
- saml::NDC ndc("doExportAssertions");
+ xmltooling::NDC ndc("doExportAssertions");
#endif
- ShibMLP mlp;
+ ExtTemplateParameters tp;
const char* procState = "Attribute Processing Error";
const char* targetURL = m_url.c_str();
);
}
}
- catch (SAMLException&) {
+ catch (exception&) {
log(LogLevelError, "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)
// Still no data?
if (!m_priv->m_cacheEntry) {
if (requireSession)
- throw InvalidSessionException("Unable to obtain session information for request.");
+ throw RetryableProfileException("Unable to obtain session information for request.");
else
- return pair<bool,void*>(false,NULL); // just bail silently
+ return make_pair(false,(void*)NULL); // just bail silently
}
// Extract data from session.
}
}
- return pair<bool,void*>(false,NULL);
+ return make_pair(false,(void*)NULL);
}
- catch (SAMLException& e) {
- mlp.insert(e);
+ catch (XMLToolingException& e) {
+ tp.m_map["errorType"] = procState;
+ tp.m_map["errorText"] = e.what();
+ if (targetURL)
+ tp.m_map["requestURL"] = m_url.substr(0,m_url.find('?'));
+ return make_pair(true,m_priv->sendError(this, "rm", tp, &e));
}
#ifndef _DEBUG
catch (...) {
- mlp.insert("errorText", "Caught an unknown exception.");
+ tp.m_map["errorType"] = procState;
+ tp.m_map["errorText"] = "Caught an unknown exception.";
+ if (targetURL)
+ tp.m_map["requestURL"] = m_url.substr(0,m_url.find('?'));
+ return make_pair(true,m_priv->sendError(this, "rm", tp));
}
#endif
-
- // If we get here then we've got an error.
- mlp.insert("errorType", procState);
-
- if (targetURL)
- mlp.insert("requestURL", m_url.substr(0,m_url.find('?')));
-
- return make_pair(true,m_priv->sendError(this, "rm", mlp));
}
const char* ShibTarget::getRequestParameter(const char* param, size_t index) const
{
static const char* defProps="; path=/";
- const IPropertySet* props=m_priv->m_app ? m_priv->m_app->getPropertySet("Sessions") : NULL;
+ 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)
bool ssl_only=false;
const char* handler=NULL;
- const IPropertySet* props=m_priv->m_app->getPropertySet("Sessions");
+ const PropertySet* props=m_priv->m_app->getPropertySet("Sessions");
if (props) {
pair<bool,bool> p=props->getBool("handlerSSL");
if (p.first)
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_priv->m_app->getId())
+ xmltooling::params(2, handler ? handler : "null", m_priv->m_app->getId())
);
// The "handlerURL" property can be in one of three formats:
return NULL;
}
-static char x2c(char *what)
-{
- register char digit;
-
- digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));
- digit *= 16;
- digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0'));
- return(digit);
-}
-
-void ShibTarget::url_decode(char* s)
-{
- register int x,y;
-
- for(x=0,y=0;s[y];++x,++y)
- {
- if((s[x] = s[y]) == '%')
- {
- s[x] = x2c(&s[y+1]);
- y+=2;
- }
- }
- s[x] = '\0';
-}
-
-static inline char hexchar(unsigned short s)
-{
- return (s<=9) ? ('0' + s) : ('A' + s - 10);
-}
-
-string ShibTarget::url_encode(const char* s)
-{
- static char badchars[]="\"\\+<>#%{}|^~[]`;/?:@=&";
-
- string ret;
- for (; *s; s++) {
- if (strchr(badchars,*s) || *s<=0x20 || *s>=0x7F) {
- ret+='%';
- ret+=hexchar(*s >> 4);
- ret+=hexchar(*s & 0x0F);
- }
- else
- ret+=*s;
- }
- return ret;
-}
-
/*************************************************************************
* Shib Target Private implementation
*/
st->m_url += uri;
}
-void* ShibTargetPriv::sendError(ShibTarget* st, const char* page, ShibMLP &mlp)
+void* 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")
};
- const IPropertySet* props=m_app->getPropertySet("Errors");
+ TemplateEngine* engine = XMLToolingConfig::getConfig().getTemplateEngine();
+ const PropertySet* props=m_app->getPropertySet("Errors");
if (props) {
pair<bool,const char*> p=props->getString(page);
if (p.first) {
ifstream infile(p.second);
- if (!infile.fail()) {
- const char* res = mlp.run(infile,props);
- if (res)
- return st->sendPage(res, 200, "text/html", ArrayIterator<ShibTarget::header_t>(hdrs,2));
+ 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));
}
}
else if (!strcmp(page,"access"))
char *value;
value=fmakeword('&',&cl,&pch);
plustospace(value);
- ShibTarget::url_decode(value);
+ opensaml::SAMLConfig::getConfig().getURLEncoder()->decode(value);
name=makeword(value,'=');
kvp_map.insert(pair<string,char*>(name,value));
free(name);