* $Id$
*/
+// SAML Runtime
+#include <saml/saml.h>
+#include <shib/shib.h>
+#include <shib/shib-threads.h>
+#include <shib-target/shib-target.h>
+
// Apache specific header files
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_log.h"
-// For POST processing from Apache
-#include <libapreq/apache_request.h>
-
-// SAML Runtime
-#include <saml/saml.h>
-#include <shib/shib.h>
-#include <shib-target/shib-target.h>
-
#include <fstream>
-#include <strstream>
+#include <sstream>
#include <stdexcept>
+// For POST processing from Apache
+#undef _XOPEN_SOURCE // bombs on solaris
+#include <libapreq/apache_request.h>
+
using namespace std;
using namespace saml;
using namespace shibboleth;
extern "C" module MODULE_VAR_EXPORT shire_module;
namespace {
+ char* g_szSHIREURL = NULL;
char* g_szSHIREConfig = NULL;
- RPCHandle *rpc_handle = NULL;
- ShibTargetConfig * g_szConfig = NULL;
-}
-
-// per-server configuration structure
-struct shire_server_config
-{
- char* serverName; // Name of this server
-};
-
-// creates the per-server configuration
-extern "C" void* create_shire_server_config (pool * p, server_rec * s)
-{
- shire_server_config* sc=(shire_server_config*)ap_pcalloc(p,sizeof(shire_server_config));
- return sc;
-}
-
-// overrides server configuration in virtual servers
-extern "C" void* merge_shire_server_config (pool* p, void* base, void* sub)
-{
- shire_server_config* sc=(shire_server_config*)ap_pcalloc(p,sizeof(shire_server_config));
- shire_server_config* parent=(shire_server_config*)base;
- shire_server_config* child=(shire_server_config*)sub;
-
- if (child->serverName)
- sc->serverName=ap_pstrdup(p,child->serverName);
- else if (parent->serverName)
- sc->serverName=ap_pstrdup(p,parent->serverName);
- else
- sc->serverName=NULL;
-
- return sc;
+ ThreadKey* rpc_handle_key = NULL;
+ ShibTargetConfig* g_Config = NULL;
}
// per-dir module configuration structure
return NULL;
}
-// generic per-server slot handlers
-extern "C" const char* ap_set_server_string_slot(cmd_parms* parms, void*, const char* arg)
-{
- char* base=(char*)ap_get_module_config(parms->server->module_config,&shire_module);
- int offset=(int)parms->info;
- *((char**)(base + offset))=ap_pstrdup(parms->pool,arg);
- return NULL;
-}
-
// some shortcuts for directory config slots
extern "C" const char* set_lifetime(cmd_parms* parms, shire_dir_config* dc, const char* arg)
{
return NULL;
}
-#ifdef SOLARIS
-extern "C"
-#endif
typedef const char* (*config_fn_t)(void);
// SHIRE Module commands
static command_rec shire_cmds[] = {
{"SHIREConfig", (config_fn_t)ap_set_global_string_slot, &g_szSHIREConfig,
RSRC_CONF, TAKE1, "Path to SHIRE ini file."},
+ {"SHIREURL", (config_fn_t)ap_set_global_string_slot, &g_szSHIREURL,
+ RSRC_CONF, TAKE1, "SHIRE POST processor URL."},
{"ShibBasicHijack", (config_fn_t)ap_set_flag_slot,
(void *) XtOffsetOf (shire_dir_config, bBasicHijack),
{NULL}
};
+namespace {
+ void destroy_handle(void* data)
+ {
+ delete (RPCHandle*)data;
+ }
+}
/*
* shire_child_init()
{
// Initialize runtime components.
- if (g_szConfig) {
+ ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s,
+ "shire_child_init() starting");
+
+ if (g_Config) {
ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,s,
"shire_child_init(): already initialized!");
exit (1);
}
try {
- g_szConfig = &(ShibTargetConfig::init(SHIBTARGET_SHIRE, g_szSHIREConfig));
- } catch (runtime_error& e) {
+ g_Config = &(ShibTargetConfig::init(SHIBTARGET_SHIRE, g_szSHIREConfig));
+ } catch (...) {
ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s,
"shire_child_init() failed to initialize SHIB Target");
exit (1);
}
- // Create the RPC Handle.. Note: this should be per _thread_
- // if there is some way to do that reasonably..
- rpc_handle = new RPCHandle(SHIB_SHAR_SOCKET, SHIBRPC_PROG, SHIBRPC_VERS_1);
+ // Create the RPC Handle TLS key.
+ rpc_handle_key=ThreadKey::create(destroy_handle);
ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s,"shire_child_init() done");
}
*/
extern "C" void shire_child_exit(server_rec* s, pool* p)
{
- delete rpc_handle;
- g_szConfig->shutdown();
- g_szConfig = NULL;
+ delete rpc_handle_key;
+ g_Config->shutdown();
+ g_Config = NULL;
ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s,"shire_child_exit() done");
}
return ret;
}
-// Return the "name" of this server to look up configuration options
-static const char* get_service_name(request_rec* r)
+static const char* get_application_id(request_rec* r)
{
- shire_server_config* sc =
- (shire_server_config*) ap_get_module_config(r->server->module_config,
- &shire_module);
-
- if (sc->serverName)
- return sc->serverName;
-
- return ap_get_server_name(r);
+ ApplicationMapper mapper;
+ return ap_pstrdup(r->pool,
+ mapper->getApplicationFromParsedURL(
+ ap_http_method(r), ap_get_server_name(r), ap_get_server_port(r), r->unparsed_uri
+ )
+ );
}
-// return the "normalized" target URL
-static const char* get_target(request_rec* r, const char* target)
+static const char* get_shire_location(request_rec* r, const char* target, const char* application_id)
{
- const char* serverName = get_service_name(r);
- string tag;
- if ((g_szConfig->getINI()).get_tag (serverName, "normalizeRequest", true, &tag))
- {
- if (ShibINI::boolean (tag))
- {
- const char* colon=strchr(target,':');
- const char* slash=strchr(colon+3,'/');
- const char* second_colon=strchr(colon+3,':');
- return ap_pstrcat(r->pool,ap_pstrndup(r->pool,target,colon+3-target),
- ap_get_server_name(r),
- (second_colon && second_colon < slash) ?
- second_colon : slash,
- NULL);
- }
- }
- return target;
-}
-
-static const char* get_shire_location(request_rec* r, const char* target, bool encode)
-{
- ShibINI& ini = g_szConfig->getINI();
- const char* serverName = get_service_name(r);
string shire_location;
+ ShibINI& ini = g_Config->getINI();
- if (! ini.get_tag (serverName, "shireURL", true, &shire_location)) {
+ if (!ini.get_tag (application_id, "shireURL", true, &shire_location)) {
ap_log_rerror(APLOG_MARK,APLOG_ERR,r,
- "shire_get_location() no shireURL configuration for %s",
- serverName);
+ "shire_get_location() no shireURL configuration for %s", application_id);
return NULL;
}
const char* shire = shire_location.c_str();
- if (*shire != '/') {
- if (encode)
- return url_encode(r,shire);
- else
+ if (*shire != '/')
return ap_pstrdup(r->pool,shire);
- }
- const char* colon=strchr(target,':');
- const char* slash=strchr(colon+3,'/');
- if (encode)
- return url_encode(r,ap_pstrcat(r->pool,
- ap_pstrndup(r->pool,target,slash-target),
- shire,NULL));
- else
- return ap_pstrcat(r->pool, ap_pstrndup(r->pool,target,slash-target),
- shire, NULL);
-}
-
-static bool is_shire_location(request_rec* r, const char* target)
-{
- const char* shire = get_shire_location(r, target, false);
- if (!shire) return false;
-
- if (!strstr(target, shire))
- return false;
-
- return (!strcmp(target,shire));
+ const char* colon=strchr(target,':');
+ const char* slash=strchr(colon+3,'/');
+ return ap_pstrcat(r->pool, ap_pstrndup(r->pool,target,slash-target), shire, NULL);
}
static int shire_error_page(request_rec* r, const char* filename, ShibMLP& mlp)
extern "C" int shire_check_user(request_rec* r)
{
- ostrstream threadid;
- threadid << "[" << getpid() << "] shire" << '\0';
- saml::NDC ndc(threadid.str());
+ ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_user: ENTER");
+ shire_dir_config* dc=(shire_dir_config*)ap_get_module_config(r->per_dir_config,&shire_module);
+
+ // This will always be normalized, because Apache uses ap_get_server_name in this API call.
+ const char* targeturl=ap_construct_url(r->pool,r->unparsed_uri,r);
+
+ // Map request to application ID, which is the key for config lookup.
+ const char* application_id=get_application_id(r);
+
+ // Get unescaped location of this application's assertion consumer service.
+ const char* unescaped_shire = get_shire_location(r, targeturl, application_id);
+
+ if (strstr(targeturl,unescaped_shire)) {
+ ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
+ "shire_check_user: REQUEST FOR SHIRE! Maybe you did not configure the SHIRE Handler?");
+ return SERVER_ERROR;
+ }
+ else {
+ // Regular access to arbitrary resource...check AuthType
+ const char *auth_type=ap_auth_type (r);
+ if (!auth_type)
+ return DECLINED;
- ShibINI& ini = g_szConfig->getINI();
- ShibMLP markupProcessor;
+ if (strcasecmp(auth_type,"shibboleth"))
+ {
+ if (!strcasecmp(auth_type,"basic") && dc->bBasicHijack==1)
+ {
+ core_dir_config* conf=
+ (core_dir_config*)ap_get_module_config(r->per_dir_config,
+ ap_find_linked_module("http_core.c"));
+ conf->ap_auth_type="shibboleth";
+ }
+ else
+ return DECLINED;
+ }
- ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
- "shire_check_user: ENTER");
+ // set the connection authtype
+ if (r->connection)
+ r->connection->ap_auth_type = "shibboleth";
+
+ // SSL check.
+ if (dc->bSSLOnly==1 && strcmp(ap_http_method(r),"https"))
+ {
+ ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"shire_check_user() blocked non-SSL access");
+ return SERVER_ERROR;
+ }
+ }
+
+ ostringstream threadid;
+ threadid << "[" << getpid() << "] shire" << '\0';
+ saml::NDC ndc(threadid.str().c_str());
- shire_dir_config* dc=
- (shire_dir_config*)ap_get_module_config(r->per_dir_config,&shire_module);
+ ShibINI& ini = g_Config->getINI();
- const char* targeturl=get_target(r,ap_construct_url(r->pool,r->unparsed_uri,r));
-
- const char * shire_location = get_shire_location(r,targeturl,true);
- if (!shire_location) return SERVER_ERROR;
- string shire_url = get_shire_location(r,targeturl,false);
+ ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
+ "shire_check_user() Shib check for %s", targeturl);
- const char* serverName = get_service_name (r);
+
string tag;
- bool has_tag = ini.get_tag (serverName, "checkIPAddress", true, &tag);
+ bool has_tag = ini.get_tag (application_id, "checkIPAddress", true, &tag);
dc->config.checkIPAddress = (has_tag ? ShibINI::boolean (tag) : false);
string shib_cookie;
- if (! ini.get_tag (serverName, "cookieName", true, &shib_cookie)) {
+ if (!ini.get_tag(application_id, "cookieName", true, &shib_cookie)) {
ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
- "shire_check_user: no cookieName configuration for %s",
- serverName);
+ "shire_check_user: no cookieName configuration for %s", application_id);
return SERVER_ERROR;
}
string wayfLocation;
- if (! ini.get_tag (serverName, "wayfURL", true, &wayfLocation)) {
+ if (!ini.get_tag(application_id, "wayfURL", true, &wayfLocation)) {
ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
- "shire_check_user: no wayfURL configuration for %s",
- serverName);
+ "shire_check_user: no wayfURL configuration for %s", application_id);
return SERVER_ERROR;
}
- string wayfError;
- if (! ini.get_tag (serverName, "wayfError", true, &wayfError)) {
+ string shireError;
+ if (!ini.get_tag(application_id, "shireError", true, &shireError)) {
ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
- "shire_check_user: no wayfError configuration for %s",
- serverName);
+ "shire_check_user: no shireError configuration for %s", application_id);
return SERVER_ERROR;
}
+
+ // Get an RPC handle and build the SHIRE object.
+ RPCHandle* rpc_handle = (RPCHandle*)rpc_handle_key->getData();
+ if (!rpc_handle)
+ {
+ rpc_handle = new RPCHandle(shib_target_sockname(), SHIBRPC_PROG, SHIBRPC_VERS_1);
+ rpc_handle_key->setData(rpc_handle);
+ }
+ SHIRE shire(rpc_handle, dc->config, unescaped_shire);
+
+ // We're in charge, so check for cookie.
+ const char* session_id=NULL;
+ const char* cookies=ap_table_get(r->headers_in,"Cookie");
- ini.get_tag (serverName, "supportContact", true, &tag);
- markupProcessor.insert ("supportContact", has_tag ? tag : "");
- has_tag = ini.get_tag (serverName, "logoLocation", true, &tag);
- markupProcessor.insert ("logoLocation", has_tag ? tag : "");
- markupProcessor.insert ("requestURL", targeturl);
+ if (cookies)
+ {
+ ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
+ "shire_check_user() cookies found: %s",cookies);
+ if (session_id=strstr(cookies,shib_cookie.c_str()))
+ {
+ // Yep, we found a cookie -- pull it out (our session_id)
+ session_id+=strlen(shib_cookie.c_str()) + 1; /* Skip over the '=' */
+ char* cookiebuf = ap_pstrdup(r->pool,session_id);
+ char* cookieend = strchr(cookiebuf,';');
+ if (cookieend)
+ *cookieend = '\0'; /* Ignore anyting after a ; */
+ session_id=cookiebuf;
+ }
+ }
- SHIRE shire(rpc_handle, dc->config, shire_url);
+ if (!session_id || !*session_id)
+ {
+ // No acceptable cookie. Redirect to WAYF.
+ ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
+ "shire_check_user() no cookie found -- redirecting to WAYF");
+ char* wayf=ap_pstrcat(r->pool,wayfLocation.c_str(),
+ "?shire=",url_encode(r,unescaped_shire),
+ "&target=",url_encode(r,targeturl),NULL);
+ ap_table_setn(r->headers_out,"Location",wayf);
+ return REDIRECT;
+ }
- if (is_shire_location (r, targeturl)) {
- // Process SHIRE POST
+ // Make sure this session is still valid
+ RPCError* status = NULL;
+ ShibMLP markupProcessor;
+ has_tag = ini.get_tag(application_id, "supportContact", true, &tag);
+ markupProcessor.insert("supportContact", has_tag ? tag : "");
+ has_tag = ini.get_tag(application_id, "logoLocation", true, &tag);
+ markupProcessor.insert("logoLocation", has_tag ? tag : "");
+ markupProcessor.insert("requestURL", targeturl);
- ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
- "shire_check_user() Beginning SHIRE POST processing");
-
+ try {
+ status = shire.sessionIsValid(session_id, r->connection->remote_ip,application_id);
+ }
+ catch (ShibTargetException &e) {
+ ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_user(): %s", e.what());
+ markupProcessor.insert ("errorType", "SHIRE Processing Error");
+ markupProcessor.insert ("errorText", e.what());
+ markupProcessor.insert ("errorDesc", "An error occurred while processing your request.");
+ return shire_error_page (r, shireError.c_str(), markupProcessor);
+ }
+ catch (...) {
+ ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_user(): caught unexpected error");
+ markupProcessor.insert ("errorType", "SHIRE Processing Error");
+ markupProcessor.insert ("errorText", "Unexpected Exception");
+ markupProcessor.insert ("errorDesc", "An error occurred while processing your request.");
+ return shire_error_page (r, shireError.c_str(), markupProcessor);
+ }
- try {
+ // Check the status
+ if (status->isError()) {
+ ap_log_rerror(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,r,
+ "shire_check_user() session invalid: %s",
+ status->getText());
+
+ if (status->isRetryable()) {
+ // Oops, session is invalid. Redirect to WAYF.
+ char* wayf=ap_pstrcat(r->pool,wayfLocation.c_str(),
+ "?shire=",url_encode(r,unescaped_shire),
+ "&target=",url_encode(r,targeturl),NULL);
+ ap_table_setn(r->headers_out,"Location",wayf);
+
+ delete status;
+ return REDIRECT;
+ }
+ else {
+ // return the error page to the user
+ markupProcessor.insert (*status);
+ delete status;
+ return shire_error_page (r, shireError.c_str(), markupProcessor);
+ }
+ }
+ else {
+ delete status;
+ ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_user() success");
+ return OK;
+ }
- string sslonly;
- if (! ini.get_tag (serverName, "shireSSLOnly", true, &sslonly))
- ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
- "shire_check_user: no shireSSLOnly configuration");
-
- // Make sure this is SSL, if it should be
- if (ShibINI::boolean(sslonly) && strcmp(ap_http_method(r),"https"))
- throw ShibTargetException (SHIBRPC_OK,
- "blocked non-SSL access to SHIRE POST processor");
-
- // Make sure this is a POST
- if (strcasecmp (r->method, "POST"))
- throw ShibTargetException (SHIBRPC_OK,
- "blocked non-POST to SHIRE POST processor");
-
- // Sure sure this POST is an appropriate content type
- const char *ct = ap_table_get (r->headers_in, "Content-type");
- if (!ct || strcasecmp (ct, "application/x-www-form-urlencoded"))
- throw ShibTargetException (SHIBRPC_OK,
- ap_psprintf(r->pool,
- "blocked bad content-type to SHIRE POST processor: %s",
- (ct ? ct : "")));
-
- // Make sure the "bytes sent" is a reasonable number
- if (r->bytes_sent > 1024*1024) // 1MB?
- throw ShibTargetException (SHIBRPC_OK,
- "blocked too-large a post to SHIRE POST processor");
-
- // Read the posted data
- ApacheRequest *ap_req = ApacheRequest_new(r);
- int err = ApacheRequest_parse(ap_req);
- if (err != OK)
- throw ShibTargetException (SHIBRPC_OK,
- ap_psprintf(r->pool,
- "ApacheRequest_parse() failed with %d.", err));
-
-
- // Make sure the target parameter exists
- const char *target = ApacheRequest_param(ap_req, "TARGET");
- if (!target || *target == '\0')
- // invalid post
- throw ShibTargetException (SHIBRPC_OK,
- "SHIRE POST failed to find TARGET");
-
- // Make sure the SAML Response parameter exists
- const char *post = ApacheRequest_param(ap_req, "SAMLResponse");
- if (!post || *post == '\0')
- // invalid post
- throw ShibTargetException (SHIBRPC_OK,
- "SHIRE POST failed to find SAMLResponse");
-
- ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
- "shire_check_user() Processing POST for target: %s", target);
-
-#if 0 // 2002-09-19
- post =
- "PFJlc3BvbnNlIHhtbG5zPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoxLjA6cHJvdG9jb2wi"
- "IHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoxLjA6cHJvdG9jb2wiIElz"
- "c3VlSW5zdGFudD0iMjAwMi0wOS0xOVQwNTozMDowMFoiIE1ham9yVmVyc2lvbj0iMSIgTWlu"
- "b3JWZXJzaW9uPSIwIiBSZWNpcGllbnQ9Imh0dHA6Ly9sb2NhbGhvc3Qvc2hpYmJvbGV0aC9T"
- "SElSRSIgUmVzcG9uc2VJRD0iYmI3ZjZmYjQtMmU0YS00YzY1LTgzY2QtYjIyMjQ0OWQwYmY4"
- "Ij48U3RhdHVzPjxTdGF0dXNDb2RlIFZhbHVlPSJzYW1scDpTdWNjZXNzIj48L1N0YXR1c0Nv"
- "ZGU+PC9TdGF0dXM+PEFzc2VydGlvbiB4bWxucz0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6"
- "MS4wOmFzc2VydGlvbiIgQXNzZXJ0aW9uSUQ9IjZhYzUxYTg2LTJhNTgtNDM2My1hZjlkLTQy"
- "YjQzYTRhMGNiZSIgSXNzdWVJbnN0YW50PSIyMDAyLTA5LTE5VDA1OjMwOjAwWiIgSXNzdWVy"
- "PSJzaGlicHJvZDAuaW50ZXJuZXQyLmVkdSIgTWFqb3JWZXJzaW9uPSIxIiBNaW5vclZlcnNp"
- "b249IjAiPjxDb25kaXRpb25zIE5vdEJlZm9yZT0iMjAwMi0wOS0xN1QwMjo1MDowMFoiIE5v"
- "dE9uT3JBZnRlcj0iMjAxMC0wOS0xOVQwNjozMDowMFoiPjxBdWRpZW5jZVJlc3RyaWN0aW9u"
- "Q29uZGl0aW9uPjxBdWRpZW5jZT5odHRwOi8vbWlkZGxld2FyZS5pbnRlcm5ldDIuZWR1L3No"
- "aWJib2xldGgvY2x1YnMvY2x1YnNoaWIvMjAwMi8wNS88L0F1ZGllbmNlPjwvQXVkaWVuY2VS"
- "ZXN0cmljdGlvbkNvbmRpdGlvbj48L0NvbmRpdGlvbnM+PEF1dGhlbnRpY2F0aW9uU3RhdGVt"
- "ZW50IEF1dGhlbnRpY2F0aW9uSW5zdGFudD0iMjAwMi0wOS0xOVQwNTozMDowMFoiIEF1dGhl"
- "bnRpY2F0aW9uTWV0aG9kPSJCYXNpYyI+PFN1YmplY3Q+PE5hbWVJZGVudGlmaWVyIE5hbWVR"
- "dWFsaWZpZXI9ImV4YW1wbGUuZWR1Ij40YzBmYjg2Yi01NjQwLTQ1ZTUtOTM3Ny1mNTJkNjhh"
- "ZDNiNjQ8L05hbWVJZGVudGlmaWVyPjxTdWJqZWN0Q29uZmlybWF0aW9uPjxDb25maXJtYXRp"
- "b25NZXRob2Q+dXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4wOmNtOkJlYXJlcjwvQ29uZmly"
- "bWF0aW9uTWV0aG9kPjwvU3ViamVjdENvbmZpcm1hdGlvbj48L1N1YmplY3Q+PFN1YmplY3RM"
- "b2NhbGl0eSBJUEFkZHJlc3M9IjE4LjEwMS4xLjEyIj48L1N1YmplY3RMb2NhbGl0eT48QXV0"
- "aG9yaXR5QmluZGluZyBBdXRob3JpdHlLaW5kPSJzYW1scDpBdHRyaWJ1dGVRdWVyeSIgQmlu"
- "ZGluZz0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4wOmJpbmRpbmdzOlNPQVAtYmluZGlu"
- "ZyIgTG9jYXRpb249Imh0dHBzOi8vc2hpYnByb2QwLmludGVybmV0Mi5lZHUvc2hpYmJvbGV0"
- "aC9BQSI+PC9BdXRob3JpdHlCaW5kaW5nPjwvQXV0aGVudGljYXRpb25TdGF0ZW1lbnQ+PC9B"
- "c3NlcnRpb24+PC9SZXNwb25zZT4K";
-#endif
-#if 0 // 2002-09-20
- post =
- "PFJlc3BvbnNlIHhtbG5zPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoxLjA6cHJvdG9jb2wi"
- "IHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoxLjA6cHJvdG9jb2wiIElz"
- "c3VlSW5zdGFudD0iMjAwMi0wOS0yMFQyMzowMDowMFoiIE1ham9yVmVyc2lvbj0iMSIgTWlu"
- "b3JWZXJzaW9uPSIwIiBSZWNpcGllbnQ9Imh0dHA6Ly9sb2NhbGhvc3Qvc2hpYmJvbGV0aC9T"
- "SElSRSIgUmVzcG9uc2VJRD0iYmI3ZjZmYjQtMmU0YS00YzY1LTgzY2QtYjIyMjQ0OWQwYmY4"
- "Ij48U3RhdHVzPjxTdGF0dXNDb2RlIFZhbHVlPSJzYW1scDpTdWNjZXNzIj48L1N0YXR1c0Nv"
- "ZGU+PC9TdGF0dXM+PEFzc2VydGlvbiB4bWxucz0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6"
- "MS4wOmFzc2VydGlvbiIgQXNzZXJ0aW9uSUQ9IjZhYzUxYTg2LTJhNTgtNDM2My1hZjlkLTQy"
- "YjQzYTRhMGNiZSIgSXNzdWVJbnN0YW50PSIyMDAyLTA5LTIwVDIzOjAwOjAwWiIgSXNzdWVy"
- "PSJzaGlicHJvZDAuaW50ZXJuZXQyLmVkdSIgTWFqb3JWZXJzaW9uPSIxIiBNaW5vclZlcnNp"
- "b249IjAiPjxDb25kaXRpb25zIE5vdEJlZm9yZT0iMjAwMi0wOS0xN1QwMjo1MDowMFoiIE5v"
- "dE9uT3JBZnRlcj0iMjAxMC0wOS0xOVQwNjozMDowMFoiPjxBdWRpZW5jZVJlc3RyaWN0aW9u"
- "Q29uZGl0aW9uPjxBdWRpZW5jZT5odHRwOi8vbWlkZGxld2FyZS5pbnRlcm5ldDIuZWR1L3No"
- "aWJib2xldGgvY2x1YnMvY2x1YnNoaWIvMjAwMi8wNS88L0F1ZGllbmNlPjwvQXVkaWVuY2VS"
- "ZXN0cmljdGlvbkNvbmRpdGlvbj48L0NvbmRpdGlvbnM+PEF1dGhlbnRpY2F0aW9uU3RhdGVt"
- "ZW50IEF1dGhlbnRpY2F0aW9uSW5zdGFudD0iMjAwMi0wOS0yMFQyMzowMDowMFoiIEF1dGhl"
- "bnRpY2F0aW9uTWV0aG9kPSJCYXNpYyI+PFN1YmplY3Q+PE5hbWVJZGVudGlmaWVyIE5hbWVR"
- "dWFsaWZpZXI9ImV4YW1wbGUuZWR1Ij40YzBmYjg2Yi01NjQwLTQ1ZTUtOTM3Ny1mNTJkNjhh"
- "ZDNiNjQ8L05hbWVJZGVudGlmaWVyPjxTdWJqZWN0Q29uZmlybWF0aW9uPjxDb25maXJtYXRp"
- "b25NZXRob2Q+dXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4wOmNtOkJlYXJlcjwvQ29uZmly"
- "bWF0aW9uTWV0aG9kPjwvU3ViamVjdENvbmZpcm1hdGlvbj48L1N1YmplY3Q+PFN1YmplY3RM"
- "b2NhbGl0eSBJUEFkZHJlc3M9IjE4LjEwMS4xLjEyIj48L1N1YmplY3RMb2NhbGl0eT48QXV0"
- "aG9yaXR5QmluZGluZyBBdXRob3JpdHlLaW5kPSJzYW1scDpBdHRyaWJ1dGVRdWVyeSIgQmlu"
- "ZGluZz0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4wOmJpbmRpbmdzOlNPQVAtYmluZGlu"
- "ZyIgTG9jYXRpb249Imh0dHBzOi8vc2hpYnByb2QwLmludGVybmV0Mi5lZHUvc2hpYmJvbGV0"
- "aC9BQSI+PC9BdXRob3JpdHlCaW5kaW5nPjwvQXV0aGVudGljYXRpb25TdGF0ZW1lbnQ+PC9B"
- "c3NlcnRpb24+PC9SZXNwb25zZT4K";
-#endif
-
- // process the post
- string cookie;
- RPCError* status = shire.sessionCreate(post, r->connection->remote_ip, cookie);
-
- if (status->isError()) {
- ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,
- "shire_check_user() POST process failed (%d): %s",
- status->status, status->error_msg.c_str());
-
- if (status->isRetryable()) {
- ap_log_rerror(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,r,
- "shire_check_user() Retrying POST by redirecting to WAYF");
-
- char* wayf=ap_pstrcat(r->pool,wayfLocation.c_str(),
- "?shire=",shire_location,
- "&target=",url_encode(r,target),NULL);
- ap_table_setn(r->headers_out,"Location",wayf);
- delete status;
- return REDIRECT;
- }
-
- // return this error to the user.
- markupProcessor.insert (*status);
- delete status;
- return shire_error_page (r, wayfError.c_str(), markupProcessor);
- }
- delete status;
-
- ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
- "shire_check_user() POST process succeeded. New cookie: %s",
- cookie.c_str());
-
- // We've got a good session, set the cookie...
- char * domain = NULL;
- char * new_cookie = ap_psprintf(r->pool, "%s=%s; path=/%s%s",
- shib_cookie.c_str(),
- cookie.c_str(),
- (domain ? "; domain=" : ""),
- (domain ? domain : ""));
-
- ap_table_setn(r->err_headers_out, "Set-Cookie", new_cookie);
- ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
- "shire_check_user() Set cookie: %s", new_cookie);
-
- // ... and redirect to the target
- char* redir=ap_pstrcat(r->pool,url_encode(r,target),NULL);
- ap_table_setn(r->headers_out, "Location", target);
- return REDIRECT;
-
- } catch (ShibTargetException &e) {
- ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
- "shire_check_user(): %s", e.what());
-
- markupProcessor.insert ("errorType", "SHIRE Processing Error");
- markupProcessor.insert ("errorText", e.what());
- return shire_error_page (r, wayfError.c_str(), markupProcessor);
- }
+ ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"shire_check_user() server error");
+ return SERVER_ERROR;
+}
- /**************************************************************************/
+extern "C" int shire_post_handler (request_rec* r)
+{
+ ostringstream threadid;
+ threadid << "[" << getpid() << "] shire" << '\0';
+ saml::NDC ndc(threadid.str().c_str());
- } else {
- // Regular access to arbitrary resource...check AuthType
+ ShibINI& ini = g_Config->getINI();
+ ShibMLP markupProcessor;
- const char *auth_type=ap_auth_type (r);
- if (!auth_type)
- return DECLINED;
+ ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_post_handler() ENTER");
- if (strcasecmp(auth_type,"shibboleth"))
- {
- if (!strcasecmp(auth_type,"basic") && dc->bBasicHijack==1)
- {
- core_dir_config* conf=
- (core_dir_config*)ap_get_module_config(r->per_dir_config,
- ap_find_linked_module("http_core.c"));
- conf->ap_auth_type="shibboleth";
- }
- else
- return DECLINED;
- }
+ // This will always be normalized, because Apache uses ap_get_server_name in this API call.
+ const char* targeturl = ap_construct_url(r->pool,r->unparsed_uri,r);
+
+ // Map request to application ID, which is the key for config lookup.
+ const char* application_id = get_application_id(r);
+
+ // The SHIRE URL is the current request URL, by definition...
+ const char* unescaped_shire = targeturl;
- ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
- "shire_check_user() Shib check for %s", targeturl);
+ string tag;
+ bool has_tag = ini.get_tag(application_id, "checkIPAddress", true, &tag);
+ SHIREConfig config;
+ config.checkIPAddress = (has_tag ? ShibINI::boolean(tag) : false);
+
+ string shib_cookie;
+ if (! ini.get_tag(application_id, "cookieName", true, &shib_cookie)) {
+ ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
+ "shire_check_user: no cookieName configuration for %s", application_id);
+ return SERVER_ERROR;
+ }
- // SSL check.
- if (dc->bSSLOnly==1 && strcmp(ap_http_method(r),"https"))
- {
- ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,
- "shire_check_user() blocked non-SSL access");
- return SERVER_ERROR;
- }
+ string wayfLocation;
+ if (! ini.get_tag(application_id, "wayfURL", true, &wayfLocation)) {
+ ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
+ "shire_check_user: no wayfURL configuration for %s", application_id);
+ return SERVER_ERROR;
+ }
- // We're in charge, so check for cookie.
- const char* session_id=NULL;
- const char* cookies=ap_table_get(r->headers_in,"Cookie");
+ string shireError;
+ if (! ini.get_tag(application_id, "shireError", true, &shireError)) {
+ ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
+ "shire_check_user: no shireError configuration for %s", application_id);
+ return SERVER_ERROR;
+ }
- if (cookies)
- ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
- "shire_check_user() cookies found: %s",
- cookies);
+ has_tag = ini.get_tag(application_id, "supportContact", true, &tag);
+ markupProcessor.insert("supportContact", has_tag ? tag : "");
+ has_tag = ini.get_tag(application_id, "logoLocation", true, &tag);
+ markupProcessor.insert("logoLocation", has_tag ? tag : "");
+ markupProcessor.insert("requestURL", targeturl);
+
+ // Get an RPC handle and build the SHIRE object.
+ RPCHandle* rpc_handle = (RPCHandle*)rpc_handle_key->getData();
+ if (!rpc_handle)
+ {
+ rpc_handle = new RPCHandle(shib_target_sockname(), SHIBRPC_PROG, SHIBRPC_VERS_1);
+ rpc_handle_key->setData(rpc_handle);
+ }
+ SHIRE shire(rpc_handle, config, unescaped_shire);
- if (!cookies || !(session_id=strstr(cookies,shib_cookie.c_str())))
- {
- // No cookie. Redirect to WAYF.
- ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
- "shire_check_user() no cookie found -- redirecting to WAYF");
- char* wayf=ap_pstrcat(r->pool,wayfLocation.c_str(),
- "?shire=",shire_location,
- "&target=",url_encode(r,targeturl),NULL);
- ap_table_setn(r->headers_out,"Location",wayf);
- return REDIRECT;
- }
+ // Process SHIRE POST
- // Yep, we found a cookie -- pull it out (our session_id)
- session_id+=strlen(shib_cookie.c_str()) + 1; /* Skip over the '=' */
- char* cookiebuf = ap_pstrdup(r->pool,session_id);
- char* cookieend = strchr(cookiebuf,';');
- if (cookieend)
- *cookieend = '\0'; /* Ignore anyting after a ; */
- session_id=cookiebuf;
+ ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
+ "shire_post_handler() Beginning SHIRE POST processing");
+
+ try {
+ string sslonly;
+ if (!ini.get_tag(application_id, "shireSSLOnly", true, &sslonly))
+ ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
+ "shire_post_handler: no shireSSLOnly configuration");
+
+ // Make sure this is SSL, if it should be
+ if (ShibINI::boolean(sslonly) && strcmp(ap_http_method(r),"https"))
+ throw ShibTargetException(SHIBRPC_OK, "blocked non-SSL access to SHIRE POST processor");
+
+ // Make sure this is a POST
+ if (strcasecmp (r->method, "POST"))
+ throw ShibTargetException(SHIBRPC_OK, "blocked non-POST to SHIRE POST processor");
+
+ // Sure sure this POST is an appropriate content type
+ const char *ct = ap_table_get (r->headers_in, "Content-type");
+ if (!ct || strcasecmp (ct, "application/x-www-form-urlencoded"))
+ throw ShibTargetException (SHIBRPC_OK,
+ ap_psprintf(r->pool,
+ "blocked bad content-type to SHIRE POST processor: %s",
+ (ct ? ct : "")));
+
+ // Make sure the "bytes sent" is a reasonable number
+ if (r->bytes_sent > 1024*1024) // 1MB?
+ throw ShibTargetException (SHIBRPC_OK,
+ "blocked too-large a post to SHIRE POST processor");
+
+ // Read the posted data
+ ApacheRequest *ap_req = ApacheRequest_new(r);
+ int err = ApacheRequest_parse(ap_req);
+ if (err != OK)
+ throw ShibTargetException (SHIBRPC_OK,
+ ap_psprintf(r->pool,
+ "ApacheRequest_parse() failed with %d.", err));
+
+
+ // Make sure the target parameter exists
+ const char *target = ApacheRequest_param(ap_req, "TARGET");
+ if (!target || *target == '\0')
+ // invalid post
+ throw ShibTargetException (SHIBRPC_OK,
+ "SHIRE POST failed to find TARGET");
+
+ // Make sure the SAML Response parameter exists
+ const char *post = ApacheRequest_param(ap_req, "SAMLResponse");
+ if (!post || *post == '\0')
+ // invalid post
+ throw ShibTargetException (SHIBRPC_OK,
+ "SHIRE POST failed to find SAMLResponse");
- // Make sure this session is still valid
- RPCError* status = shire.sessionIsValid(session_id, r->connection->remote_ip);
+ ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
+ "shire_post_handler() Processing POST for target: %s", target);
- // Check the status
- if (status->isError()) {
+ // process the post
+ string cookie;
+ RPCError* status = shire.sessionCreate(post, r->connection->remote_ip, application_id, cookie);
- ap_log_rerror(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,r,
- "shire_check_user() session invalid: %s",
- status->error_msg.c_str());
+ if (status->isError()) {
+ ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,
+ "shire_post_handler() POST process failed (%d): %s",
+ status->getCode(), status->getText());
- // Oops, session is invalid. Redirect to WAYF.
+ if (status->isRetryable()) {
+ ap_log_rerror(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,r,
+ "shire_post_handler() Retrying POST by redirecting to WAYF");
+
char* wayf=ap_pstrcat(r->pool,wayfLocation.c_str(),
- "?shire=",shire_location,
- "&target=",url_encode(r,targeturl),NULL);
- ap_table_setn(r->headers_out,"Location",wayf);
-
- delete status;
- return REDIRECT;
+ "?shire=",url_encode(r,unescaped_shire),
+ "&target=",url_encode(r,target),NULL);
+ ap_table_setn(r->headers_out,"Location",wayf);
+ delete status;
+ return REDIRECT;
+ }
- } else {
- delete status;
- ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
- "shire_check_user() success");
- return OK;
- }
+ // return this error to the user.
+ markupProcessor.insert (*status);
+ delete status;
+ return shire_error_page (r, shireError.c_str(), markupProcessor);
}
+ delete status;
- ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,
- "shire_check_user() server error");
- return SERVER_ERROR;
+ ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
+ "shire_post_handler() POST process succeeded. New cookie: %s",
+ cookie.c_str());
+
+ // We've got a good session, set the cookie...
+ char * domain = NULL;
+ char * new_cookie = ap_psprintf(r->pool, "%s=%s; path=/%s%s",
+ shib_cookie.c_str(),
+ cookie.c_str(),
+ (domain ? "; domain=" : ""),
+ (domain ? domain : ""));
+
+ ap_table_setn(r->err_headers_out, "Set-Cookie", new_cookie);
+ ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
+ "shire_post_handler() Set cookie: %s", new_cookie);
+
+ // ... and redirect to the target
+ char* redir=ap_pstrcat(r->pool,url_encode(r,target),NULL);
+ ap_table_setn(r->headers_out, "Location", target);
+ return REDIRECT;
+
+ } catch (ShibTargetException &e) {
+ ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
+ "shire_post_handler(): %s", e.what());
+
+ markupProcessor.insert ("errorType", "SHIRE Processing Error");
+ markupProcessor.insert ("errorText", e.what());
+ markupProcessor.insert ("errorDesc", "An error occurred while processing your request.");
+ return shire_error_page (r, shireError.c_str(), markupProcessor);
+ }
+ catch (...) {
+ ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_post_handler(): unexpected exception");
+
+ markupProcessor.insert ("errorType", "SHIRE Processing Error");
+ markupProcessor.insert ("errorText", "Unexpected Exception");
+ markupProcessor.insert ("errorDesc", "An error occurred while processing your request.");
+ return shire_error_page (r, shireError.c_str(), markupProcessor);
+ }
+
+ ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"shire_post_handler() server error");
+ return SERVER_ERROR;
}
extern "C"{
+handler_rec shire_handlers[] = {
+ { "shib-shire-post", shire_post_handler },
+ { NULL }
+};
+
+extern "C" void mod_shire_init (server_rec*r, pool* p)
+{
+ ShibTargetConfig::preinit();
+}
+
module MODULE_VAR_EXPORT shire_module = {
STANDARD_MODULE_STUFF,
- NULL, /* initializer */
+ mod_shire_init, /* initializer */
create_shire_dir_config, /* dir config creater */
merge_shire_dir_config, /* dir merger --- default is to override */
- create_shire_server_config, /* server config */
- merge_shire_server_config, /* merge server config */
+ NULL, /* server config */
+ NULL, /* merge server config */
shire_cmds, /* command table */
- NULL, /* handlers */
+ shire_handlers, /* handlers */
NULL, /* filename translation */
shire_check_user, /* check_user_id */
NULL, /* check auth */