From d4cedb7b17ad5c31e601a63a996503b625e3abac Mon Sep 17 00:00:00 2001 From: Derek Atkins Date: Tue, 23 Sep 2003 23:58:43 +0000 Subject: [PATCH] First pass at an apache-2 module. It compiles on Linux but it wont work, yet. --- Makefile.am | 2 +- apache-2.0/.gitignore | 8 + apache-2.0/Makefile.am | 25 ++ apache-2.0/mod_shib.cpp | 691 ++++++++++++++++++++++++++++++++++++++++++++++++ configure.ac | 246 +++++++++++++++-- 5 files changed, 951 insertions(+), 21 deletions(-) create mode 100644 apache-2.0/.gitignore create mode 100644 apache-2.0/Makefile.am create mode 100644 apache-2.0/mod_shib.cpp diff --git a/Makefile.am b/Makefile.am index eef83e8..a1181cc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -22,4 +22,4 @@ WANT_SUBDIRS = @WANT_SUBDIRS@ SUBDIRS = $(WANT_SUBDIRS) DIST_SUBDIRS = doc oncrpc shib schemas configs shib-target shar test \ - mod_shire mod_shibrm siterefresh shib-mysql-ccache + mod_shire mod_shibrm apache-2.0 siterefresh shib-mysql-ccache diff --git a/apache-2.0/.gitignore b/apache-2.0/.gitignore new file mode 100644 index 0000000..7bf9d81 --- /dev/null +++ b/apache-2.0/.gitignore @@ -0,0 +1,8 @@ +/Makefile.in +/Makefile +/.libs +/.deps +/*.lo +/*.la +/Debug +/*.plg \ No newline at end of file diff --git a/apache-2.0/Makefile.am b/apache-2.0/Makefile.am new file mode 100644 index 0000000..1b6fc49 --- /dev/null +++ b/apache-2.0/Makefile.am @@ -0,0 +1,25 @@ +## $Id$ + +AUTOMAKE_OPTIONS = foreign + +if USE_OUR_ONCRPC +RPC_CFLAGS = -I${top_srcdir}/oncrpc +endif + +modshibdir = $(libexecdir) +modshib_LTLIBRARIES = mod_shib.la + +mod_shib_la_SOURCES = mod_shib.cpp + +AM_CXXFLAGS = $(APXS2_CFLAGS) -I$(APXS2_INCLUDE) $(RPC_CFLAGS) + +mod_shib_la_LIBADD = $(top_builddir)/shib/libshib.la $(top_builddir)/shib-target/libshib-target.la + +mod_shib_la_LDFLAGS = -module -avoid-version -lapreq + +if DO_APXS2_INSTALL +install-exec-local: + $(APXS2) -i -A -n shib .libs/mod_shib.so +endif + +EXTRA_DIST = mod_shib.dsp diff --git a/apache-2.0/mod_shib.cpp b/apache-2.0/mod_shib.cpp new file mode 100644 index 0000000..5094eda --- /dev/null +++ b/apache-2.0/mod_shib.cpp @@ -0,0 +1,691 @@ +/* + * mod_shib.cpp -- Shibboleth module for Apache-2.0 + * + * Created by: Derek Atkins + * + * $Id$ + */ + +// SAML Runtime +#include +#include +#include +#include + +// Apache specific header files +#include +#include +#include +#include +#include +#include +#define CORE_PRIVATE +#include +#include + +#include +#include +#include + +// For POST processing from Apache +//-- do we still need this? #undef _XOPEN_SOURCE // bombs on solaris +#include + +#include // for getpid() + +using namespace std; +using namespace saml; +using namespace shibboleth; +using namespace shibtarget; + +extern "C" AP_MODULE_DECLARE_DATA module mod_shib; + +namespace { + char* g_szSHIREURL = NULL; + char* g_szSHIBConfig = NULL; + ThreadKey* rpc_handle_key = NULL; + ShibTargetConfig* g_Config = NULL; +} + +// per-dir module configuration structure +struct shib_dir_config +{ + int bBasicHijack; // activate for AuthType Basic? + int bSSLOnly; // only over SSL? + SHIREConfig config; // SHIB Configuration + RMConfig rm_config; // RM Configuration +}; + +// creates per-directory config structure +extern "C" void* create_shib_dir_config (apr_pool_t* p, char* d) +{ + shib_dir_config* dc=(shib_dir_config*)apr_pcalloc(p,sizeof(shib_dir_config)); + dc->bBasicHijack = -1; + dc->bSSLOnly = -1; + dc->config.lifetime = -1; + dc->config.timeout = -1; + return dc; +} + +// overrides server configuration in directories +extern "C" void* merge_shib_dir_config (apr_pool_t* p, void* base, void* sub) +{ + shib_dir_config* dc=(shib_dir_config*)apr_pcalloc(p,sizeof(shib_dir_config)); + shib_dir_config* parent=(shib_dir_config*)base; + shib_dir_config* child=(shib_dir_config*)sub; + + dc->bBasicHijack=((child->bBasicHijack==-1) ? parent->bBasicHijack : child->bBasicHijack); + dc->bSSLOnly=((child->bSSLOnly==-1) ? parent->bSSLOnly : child->bSSLOnly); + dc->config.lifetime=((child->config.lifetime==-1) ? parent->config.lifetime : child->config.lifetime); + dc->config.timeout=((child->config.timeout==-1) ? parent->config.timeout : child->config.timeout); + return dc; +} + +// generic global slot handlers +extern "C" const char* ap_set_global_string_slot(cmd_parms* parms, void*, const char* arg) +{ + *((char**)(parms->info))=apr_pstrdup(parms->pool,arg); + return NULL; +} + +// some shortcuts for directory config slots +extern "C" const char* set_lifetime(cmd_parms* parms, shib_dir_config* dc, const char* arg) +{ + dc->config.lifetime=atoi(arg); + return NULL; +} + +extern "C" const char* set_timeout(cmd_parms* parms, shib_dir_config* dc, const char* arg) +{ + dc->config.timeout=atoi(arg); + return NULL; +} + +typedef const char* (*config_fn_t)(void); + +// SHIB Module commands + +static command_rec shib_cmds[] = { + {"SHIBConfig", (config_fn_t)ap_set_global_string_slot, &g_szSHIBConfig, + RSRC_CONF, TAKE1, "Path to SHIB 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 *) offsetof (shib_dir_config, bBasicHijack), + OR_AUTHCFG, FLAG, "Respond to AuthType Basic and convert to shib?"}, + {"ShibSSLOnly", (config_fn_t)ap_set_flag_slot, + (void *) offsetof (shib_dir_config, bSSLOnly), + OR_AUTHCFG, FLAG, "Require SSL when accessing a secured directory?"}, + {"ShibAuthLifetime", (config_fn_t)set_lifetime, NULL, + OR_AUTHCFG, TAKE1, "Lifetime of session in seconds."}, + {"ShibAuthTimeout", (config_fn_t)set_timeout, NULL, + OR_AUTHCFG, TAKE1, "Timeout for session in seconds."}, + + {NULL} +}; + +namespace { + void destroy_handle(void* data) + { + delete (RPCHandle*)data; + } +} + +/* + * shib_child_init() + * Things to do when the child process is initialized. + */ +extern "C" void shib_child_init(server_rec* s, apr_pool_t* p) +{ + // Initialize runtime components. + + ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,s, + "shib_child_init() starting"); + + if (g_Config) { + ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,0,s, + "shib_child_init(): already initialized!"); + exit (1); + } + + try { + g_Config = &(ShibTargetConfig::init(SHIBTARGET_SHIRE, g_szSHIBConfig)); + } catch (...) { + ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,s, + "shib_child_init() failed to initialize SHIB Target"); + exit (1); + } + + // Create the RPC Handle TLS key. + rpc_handle_key=ThreadKey::create(destroy_handle); + + ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,s,"shib_child_init() done"); +} + + +/* + * shib_child_exit() + * Cleanup. + */ +extern "C" void shib_child_exit(server_rec* s, apr_pool_t* p) +{ + delete rpc_handle_key; + g_Config->shutdown(); + g_Config = NULL; + ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,s,"shib_child_exit() done"); +} + +inline char hexchar(unsigned short s) +{ + return (s<=9) ? ('0' + s) : ('A' + s - 10); +} + +static char* url_encode(request_rec* r, const char* s) +{ + static char badchars[]="\"\\+<>#%{}|^~[]`;/?:@=&"; + char* ret=(char*)apr_palloc(r->pool,sizeof(char)*3*strlen(s)+1); + + unsigned long count=0; + for (; *s; s++) + { + if (strchr(badchars,*s)!=NULL || *s<=0x1F || *s>=0x7F) + { + ret[count++]='%'; + ret[count++]=hexchar(*s >> 4); + ret[count++]=hexchar(*s & 0x0F); + } + else + ret[count++]=*s; + } + ret[count++]=*s; + return ret; +} + +static const char* get_shire_location(request_rec* r, const char* target, bool encode) +{ + ShibINI& ini = g_Config->getINI(); + string shire_location; + + if (g_szSHIREURL) + shire_location = g_szSHIREURL; + else if (! ini.get_tag (ap_get_server_name(r), "shireURL", true, &shire_location)) { + ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r, + "shire_get_location() no shireURL configuration for %s", + ap_get_server_name(r)); + return NULL; + } + + const char* shire = shire_location.c_str(); + + if (*shire != '/') { + if (encode) + return url_encode(r,shire); + else + return apr_pstrdup(r->pool,shire); + } + const char* colon=strchr(target,':'); + const char* slash=strchr(colon+3,'/'); + if (encode) + return url_encode(r,apr_pstrcat(r->pool, + apr_pstrndup(r->pool,target,slash-target), + shire,NULL)); + else + return apr_pstrcat(r->pool, apr_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)); +} + +static int shib_error_page(request_rec* r, const char* filename, ShibMLP& mlp) +{ + ifstream infile (filename); + if (!infile) { + ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r, + "shib_error_page() cannot open %s", filename); + return HTTP_INTERNAL_SERVER_ERROR; + } + + string res = mlp.run(infile); + r->content_type = apr_psprintf(r->pool, "text/html"); + ap_rprintf(r, res.c_str()); + return DONE; +} + +extern "C" int shib_check_user(request_rec* r) +{ + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r,"shib_check_user: ENTER"); + shib_dir_config* dc=(shib_dir_config*)ap_get_module_config(r->per_dir_config,&mod_shib); + + // This will always be normalized, because Apache uses ap_get_server_name in this API call. + char* targeturl=ap_construct_url(r->pool,r->unparsed_uri,r); + + if (is_shire_location (r, targeturl)) { + ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,0,r, + "shib_check_user: REQUEST FOR SHIRE! Maybe you did not configure the SHIRE Handler?"); + return HTTP_INTERNAL_SERVER_ERROR; + } + else { + // Regular access to arbitrary resource...check AuthType + const char *auth_type=ap_auth_type (r); + if (!auth_type) + return DECLINED; + + 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; + } + + // set the connection authtype + r->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,0,r, + "shib_check_user() blocked non-SSL access"); + return HTTP_INTERNAL_SERVER_ERROR; + } + } + + ostringstream threadid; + threadid << "[" << getpid() << "] shib" << '\0'; + saml::NDC ndc(threadid.str().c_str()); + + ShibINI& ini = g_Config->getINI(); + + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, + "shib_check_user() Shib check for %s", targeturl); + + + const char * shire_location = get_shire_location(r,targeturl,true); + if (!shire_location) + return HTTP_INTERNAL_SERVER_ERROR; + string shire_url = get_shire_location(r,targeturl,false); + + const char* serverName = ap_get_server_name(r); + string tag; + bool has_tag = ini.get_tag (serverName, "checkIPAddress", true, &tag); + dc->config.checkIPAddress = (has_tag ? ShibINI::boolean (tag) : false); + + string shib_cookie; + if (! ini.get_tag(serverName, "cookieName", true, &shib_cookie)) { + ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,0,r, + "shib_check_user: no cookieName configuration for %s", + serverName); + return HTTP_INTERNAL_SERVER_ERROR; + } + + string wayfLocation; + if (! ini.get_tag(serverName, "wayfURL", true, &wayfLocation)) { + ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,0,r, + "shib_check_user: no wayfURL configuration for %s", + serverName); + return HTTP_INTERNAL_SERVER_ERROR; + } + + string shireError; + if (! ini.get_tag(serverName, "shireError", true, &shireError)) { + ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,0,r, + "shib_check_user: no shireError configuration for %s", + serverName); + return HTTP_INTERNAL_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, shire_url); + + // We're in charge, so check for cookie. + const char* session_id=NULL; + const char* cookies=apr_table_get(r->headers_in,"Cookie"); + + if (cookies) + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, + "shib_check_user() cookies found: %s",cookies); + + if (!cookies || !(session_id=strstr(cookies,shib_cookie.c_str()))) + { + // No cookie. Redirect to WAYF. + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, + "shib_check_user() no cookie found -- redirecting to WAYF"); + char* wayf=apr_pstrcat(r->pool,wayfLocation.c_str(), + "?shire=",shire_location, + "&target=",url_encode(r,targeturl),NULL); + apr_table_setn(r->headers_out,"Location",wayf); + return HTTP_MOVED_TEMPORARILY; + } + + // Yep, we found a cookie -- pull it out (our session_id) + session_id+=strlen(shib_cookie.c_str()) + 1; /* Skip over the '=' */ + char* cookiebuf = apr_pstrdup(r->pool,session_id); + char* cookieend = strchr(cookiebuf,';'); + if (cookieend) + *cookieend = '\0'; /* Ignore anyting after a ; */ + session_id=cookiebuf; + + // Make sure this session is still valid + RPCError* status = NULL; + ShibMLP markupProcessor; + has_tag = 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); + + try { + status = shire.sessionIsValid(session_id, r->connection->remote_ip,targeturl); + } + catch (ShibTargetException &e) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r,"shib_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 shib_error_page (r, shireError.c_str(), markupProcessor); + } + catch (...) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r,"shib_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 shib_error_page (r, shireError.c_str(), markupProcessor); + } + + // Check the status + if (status->isError()) { + ap_log_rerror(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,0,r, + "shib_check_user() session invalid: %s", + status->getText()); + + if (status->isRetryable()) { + // Oops, session is invalid. Redirect to WAYF. + char* wayf=apr_pstrcat(r->pool,wayfLocation.c_str(), + "?shire=",shire_location, + "&target=",url_encode(r,targeturl),NULL); + apr_table_setn(r->headers_out,"Location",wayf); + + delete status; + return HTTP_MOVED_TEMPORARILY; + } + else { + // return the error page to the user + markupProcessor.insert (*status); + delete status; + return shib_error_page (r, shireError.c_str(), markupProcessor); + } + } + else { + delete status; + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, + "shib_check_user() success"); + return OK; + } + + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,0,r,"shib_check_user() server error"); + return HTTP_INTERNAL_SERVER_ERROR; +} + +extern "C" int shire_post_handler (request_rec* r) +{ + ostringstream threadid; + threadid << "[" << getpid() << "] shire" << '\0'; + saml::NDC ndc(threadid.str().c_str()); + + ShibINI& ini = g_Config->getINI(); + ShibMLP markupProcessor; + + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r,"shire_post_handler() ENTER"); + + const char* targeturl=ap_construct_url(r->pool,r->unparsed_uri,r); + + const char * shire_location = get_shire_location(r,targeturl,true); + if (!shire_location) + return HTTP_INTERNAL_SERVER_ERROR; + string shire_url = get_shire_location(r,targeturl,false); + + const char* serverName = ap_get_server_name(r); + string tag; + bool has_tag = ini.get_tag(serverName, "checkIPAddress", true, &tag); + SHIREConfig config; + config.checkIPAddress = (has_tag ? ShibINI::boolean(tag) : false); + + string shib_cookie; + if (! ini.get_tag(serverName, "cookieName", true, &shib_cookie)) { + ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,0,r, + "shire_post_handler: no cookieName configuration for %s", + serverName); + return HTTP_INTERNAL_SERVER_ERROR; + } + + string wayfLocation; + if (! ini.get_tag(serverName, "wayfURL", true, &wayfLocation)) { + ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,0,r, + "shire_post_handler: no wayfURL configuration for %s", + serverName); + return HTTP_INTERNAL_SERVER_ERROR; + } + + string shireError; + if (! ini.get_tag(serverName, "shireError", true, &shireError)) { + ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,0,r, + "shire_post_handler: no shireError configuration for %s", + serverName); + return HTTP_INTERNAL_SERVER_ERROR; + } + + has_tag = 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); + + // 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, shire_url); + + // Process SHIRE POST + + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, + "shire_post_handler() Beginning SHIRE POST processing"); + + try { + string sslonly; + if (!ini.get_tag(serverName, "shireSSLOnly", true, &sslonly)) + ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,0,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 = apr_table_get (r->headers_in, "Content-type"); + if (!ct || strcasecmp (ct, "application/x-www-form-urlencoded")) + throw ShibTargetException (SHIBRPC_OK, + apr_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 + apreq_request_t *ap_req = apreq_request(r, NULL); + if (!ap_req) + throw ShibTargetException (SHIBRPC_OK, + apr_psprintf(r->pool, "apreq_request() failed")); + + // Make sure the target parameter exists + apreq_param_t *param = apreq_param(ap_req, "TARGET"); + const char *target = param ? apreq_param_value(param) : NULL; + if (!target || *target == '\0') + // invalid post + throw ShibTargetException (SHIBRPC_OK, + "SHIRE POST failed to find TARGET"); + + // Make sure the SAML Response parameter exists + param = apreq_param(ap_req, "SAMLResponse"); + const char *post = param ? apreq_param_value(param) : NULL; + 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,0,r, + "shire_post_handler() Processing POST for target: %s", target); + + // 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,0,r, + "shire_post_handler() POST process failed (%d): %s", + status->getCode(), status->getText()); + + if (status->isRetryable()) { + ap_log_rerror(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,0,r, + "shire_post_handler() Retrying POST by redirecting to WAYF"); + + char* wayf=apr_pstrcat(r->pool,wayfLocation.c_str(), + "?shire=",shire_location, + "&target=",url_encode(r,target),NULL); + apr_table_setn(r->headers_out,"Location",wayf); + delete status; + return HTTP_MOVED_TEMPORARILY; + } + + // return this error to the user. + markupProcessor.insert (*status); + delete status; + return shib_error_page (r, shireError.c_str(), markupProcessor); + } + delete status; + + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,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 = apr_psprintf(r->pool, "%s=%s; path=/%s%s", + shib_cookie.c_str(), + cookie.c_str(), + (domain ? "; domain=" : ""), + (domain ? domain : "")); + + apr_table_setn(r->err_headers_out, "Set-Cookie", new_cookie); + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,r, + "shire_post_handler() Set cookie: %s", new_cookie); + + // ... and redirect to the target + char* redir=apr_pstrcat(r->pool,url_encode(r,target),NULL); + apr_table_setn(r->headers_out, "Location", target); + return HTTP_MOVED_TEMPORARILY; + + } catch (ShibTargetException &e) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,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 shib_error_page (r, shireError.c_str(), markupProcessor); + } + catch (...) { + ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,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 shib_error_page (r, shireError.c_str(), markupProcessor); + } + + ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,0,r,"shire_post_handler() server error"); + return HTTP_INTERNAL_SERVER_ERROR; +} + +#if 0 +extern "C"{ +handler_rec shib_handlers[] = { + { "shib-shire-post", shire_post_handler }, + { NULL } +}; +#endif + +extern "C" void mod_shib_init (server_rec*r, apr_pool_t* p) +{ + ShibTargetConfig::preinit(); +} + +extern "C" { +command_rec shib_commands[] = { + +}; + +void shib_register_hooks (apr_pool_t *p) +{ +} + +module AP_MODULE_DECLARE_DATA mod_shib = { + STANDARD20_MODULE_STUFF, + create_shib_dir_config, /* create dir config */ + merge_shib_dir_config, /* merge dir config --- default is to override */ + NULL, /* create server config */ + NULL, /* merge server config */ + shib_commands, /* command table */ + shib_register_hooks /* register hooks */ +}; +} /* extern "C" */ + +#if 0 + shib_handlers, + mod_shib_init, /* initializer */ + NULL, /* filename translation */ + shib_check_user, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + NULL, /* fixups */ + NULL, /* logger */ + NULL, /* header parser */ + shib_child_init, /* child_init */ + shib_child_exit, /* child_exit */ + NULL /* post read-request */ +#endif diff --git a/configure.ac b/configure.ac index 5aec266..0b83fbe 100644 --- a/configure.ac +++ b/configure.ac @@ -185,22 +185,26 @@ AM_CONDITIONAL(USE_OUR_ONCRPC,test "$rpctest" = "no") # types (Apache 1/2, iPlanet, others). # Apache 1.3 (mod_shire/mod_shibrm) -# --with-apache (static build, no idea how to do this yet, so not supported) -# --with-apxs (DSO build, the normal way, uses apxs to derive build flags) -# --without-apxs (DSO build, you tell us how to build using the environment) +# --with-apache-13 (static build, no idea how to do this yet, so not supported) +# --with-apxs (DSO build, the normal way, uses apxs to derive build flags) +# --without-apxs (DSO build, you tell us how to build using the environment) AC_ARG_ENABLE(apache-13, - AC_HELP_STRING([--disable-apache-13], [disable the Apache 1.3 modules])) -if test "x$enable_apache_13" = "x" ; then - enable_apache_13=yes + AC_HELP_STRING([--enable-apache-13], [enable the Apache 1.3 modules]), + [ if test "x$enableval" = "x" ; then + WANT_APACHE_13=yes + else + WANT_APACHE_13="$enableval" + fi + ], [ WANT_APACHE_13=no ]) +AC_MSG_CHECKING(whether to build Apache-1.3 support) +if test "$WANT_APACHE_13" != yes && test "$WANT_APACHE_13" != no ; then + WANT_APACHE_13=yes fi +AC_MSG_RESULT($WANT_APACHE_13) -if test "$enable_apache_13" != yes ; then - AC_MSG_WARN(Building without Apache...) - WANT_APACHE=no -else +if test "$WANT_APACHE_13" = yes ; then -AC_MSG_CHECKING([for dynamic Apache module support (w/ or w/o APXS)]) AC_ARG_WITH(apxs, [ --with-apxs[=FILE] Build shared Apache module(s). FILE is the optional pathname to the Apache apxs tool; defaults to "apxs".], @@ -217,8 +221,12 @@ AC_ARG_WITH(apxs, else APXS="$withval" fi +], +[ + AC_PATH_PROG(APXS, apxs, no) ]) +AC_MSG_CHECKING([for dynamic Apache-1.3 module support (w/ or w/o APXS)]) if test "$APXS" = "no"; then # --without-apxs means you want the modules, @@ -281,7 +289,7 @@ if test "$APXS" = "no"; then fi AC_MSG_NOTICE([APXS_SYSCONFDIR is $APXS_SYSCONFDIR]) - WANT_APACHE="yes" + WANT_APACHE_13="yes" elif test -n "$APXS"; then @@ -302,19 +310,16 @@ elif test -n "$APXS"; then more information.]) fi - WANT_APACHE="yes" + WANT_APACHE_13="yes" else # guess we're not doing Apache 1.3 AC_MSG_RESULT(no) - WANT_APACHE="no" + WANT_APACHE_13="no" fi - fi -AM_CONDITIONAL(HAVE_APXS,test -n "$APXS") - -if test "$WANT_APACHE" = "yes"; then +if test "$WANT_APACHE_13" = "yes"; then AC_ARG_WITH(apreq, AC_HELP_STRING([--with-apreq=PATH], [where libapreq is installed]), [if test x_$with_apreq != x_/usr; then @@ -361,9 +366,198 @@ dnl LIBS="$saved_LIBS" fi # always output the Makefile, even if we don't use it AC_CONFIG_FILES([mod_shire/Makefile mod_shibrm/Makefile]) - +AM_CONDITIONAL(HAVE_APXS,test -n "$APXS") AM_CONDITIONAL(DO_APXS_INSTALL,test -n "$APXS_INSTALL") + +# Apache 2.0 (mod_shib in apache-2.0) +# --with-apache-20 (static build, no idea how to do this yet, so not supported) +# --with-apxs2 (DSO build, the normal way, uses apxs to derive build flags) +# --without-apxs2 (DSO build, you tell us how to build using the environment) + +AC_ARG_ENABLE(apache-20, + AC_HELP_STRING([--enable-apache-20], [enable the Apache 2.0 modules]), + [ if test "x$enableval" = "x" ; then + WANT_APACHE_20=yes + else + WANT_APACHE_20="$enableval" + fi + ], [ WANT_APACHE_20=no ]) + +AC_MSG_CHECKING(whether to build Apache-2.0 support) +if test "$WANT_APACHE_20" != yes && test "$WANT_APACHE_20" != no ; then + WANT_APACHE_20=yes +fi +AC_MSG_RESULT($WANT_APACHE_20) + +if test "$WANT_APACHE_20" = yes ; then + +AC_ARG_WITH(apxs2, +[ --with-apxs2[=FILE] Build shared Apache module(s). FILE is the optional + pathname to the Apache apxs tool; defaults to "apxs".], +[ + if test "$withval" = "yes"; then + for i in /usr/sbin /usr/local/apache/bin ; do + if test -f "$i/apxs"; then + APXS2="$i/apxs" + fi + done + if test -z "$APXS2"; then + APXS2=apxs + fi + else + APXS2="$withval" + fi +], +[ + AC_PATH_PROG(APXS2, apxs, no) +]) + +AC_MSG_CHECKING([for dynamic Apache-2 module support (w/ or w/o APXS)]) +if test "$APXS2" = "no"; then + + # --without-apxs2 means you want the modules, + # but want to tell us how to build them + AC_MSG_RESULT(yes, but use environment, not apxs) + echo + echo "Did you set one or more of these?" + echo + echo "APXS2_CFLAGS APXS2_PREFIX APXS2_INCLUDE APXS2_LIBEXEC APXS2_SYSCONFDIR" + echo + + AC_MSG_NOTICE([APXS2_CFLAGS is $APXS2_CFLAGS]) + + # try and find the Apache root + if test -z "$APXS2_PREFIX"; then + if test -d "/usr/local/apache"; then + APXS2_PREFIX="/usr/local/apache" + else + AC_MSG_ERROR([You MUST set APXS2_PREFIX so the right Apache-2 can be located!]) + fi + elif test ! -d "$APXS2_PREFIX"; then + AC_MSG_ERROR([APXS2_PREFIX of $APXS2_PREFIX cannot be found]) + fi + AC_MSG_NOTICE([APXS2_PREFIX is $APXS2_PREFIX]) + + + # other subfolders might be derived from APXS2_PREFIX + if test -z "$APXS2_INCLUDE"; then + if test -f "$APXS2_PREFIX/include/httpd.h"; then + APXS2_INCLUDE="$APXS2_PREFIX/include" + else + AC_MSG_ERROR([can't find Apache-2 include files beneath $APXS2_PREFIX]) + fi + elif ! test -f "$APXS2_INCLUDE/httpd.h"; then + AC_MSG_ERROR([APXS2_INCLUDE of $APXS2_INCLUDE does not contain Apache-2 headers]) + fi + AC_MSG_NOTICE([APXS2_INCLUDE is $APXS2_INCLUDE]) + + if test -z "$APXS2_LIBEXEC"; then + if test -d "$APXS2_PREFIX/libexec"; then + APXS2_LIBEXEC="$APXS2_PREFIX/libexec" + elif test -d "$APXS2_PREFIX/modules"; then + APXS2_LIBEXEC="$APXS2_PREFIX/modules" + else + AC_MSG_ERROR([can't find Apache-2 libexec/module directory beneath $APXS2_PREFIX]) + fi + elif ! test -d "$APXS2_LIBEXEC"; then + AC_MSG_ERROR([APXS2_LIBEXEC of $APXS2_LIBEXEC does not exist]) + fi + AC_MSG_NOTICE([APXS2_LIBEXEC is $APXS2_LIBEXEC]) + + if test -z "$APXS2_SYSCONFDIR"; then + if test -d "$APXS2_PREFIX/conf"; then + APXS2_SYSCONFDIR="$APXS2_PREFIX/conf" + else + AC_MSG_ERROR([can't find Apache-2 conf directory beneath $APXS2_PREFIX]) + fi + elif ! test -d "$APXS2_SYSCONFDIR"; then + AC_MSG_ERROR([APXS2_SYSCONFDIR of $APXS2_SYSCONFDIR does not exist]) + fi + AC_MSG_NOTICE([APXS2_SYSCONFDIR is $APXS2_SYSCONFDIR]) + + WANT_APACHE_20="yes" + +elif test -n "$APXS2"; then + + # extract settings we need from APXS2 -q + APXS2_CC="`$APXS2 -q CC`" + APXS2_CFLAGS="`$APXS2 -q CFLAGS` `$APXS2 -q CFLAGS_SHLIB`" + APXS2_INCLUDE="`$APXS2 -q INCLUDEDIR`" + APXS2_LIBEXEC="`$APXS2 -q LIBEXECDIR`" + APXS2_SYSCONFDIR="`$APXS2 -q SYSCONFDIR`" + + AC_SUBST(APXS2) + AC_MSG_RESULT(found at $APXS2) + + if test -z "`$APXS2 -q LD_SHLIB`" && test -z "`$APXS2 -q LIBEXECDIR`" \ + || test "$APXS2_LIBEXEC" = "modules"; then + AC_MSG_ERROR( +[Your APXS installation is broken and cannot be used. + Please see http://www.webdav.org/mod_dav/install.html#apxs for + more information.]) + fi + + WANT_APACHE_20="yes" + +else + # guess we're not doing Apache 2.0 + AC_MSG_RESULT(no) + WANT_APACHE_20="no" +fi +fi + +if test "$WANT_APACHE_20" = "yes"; then + AC_ARG_WITH(apreq2, + AC_HELP_STRING([--with-apreq2=PATH], [where http-apreq-2 is installed]), + [if test x_$with_apreq2 != x_/usr; then + LDFLAGS="-L${with_apreq2}/lib $LDFLAGS" + CPPFLAGS="-I${with_apreq2}/include $CPPFLAGS" + fi]) + + saved_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="-I$APXS2_INCLUDE $APXS2_CFLAGS $CPPFLAGS" + AC_TRY_COMPILE([#include ], + [int i=0], + test_apreq2="yes",test_apreq2="no") + if test "$test_apreq2" = "no"; then + CPPFLAGS="$CPPFLAGS -U_XOPEN_SOURCE" + APXS2_CFLAGS="$APXS2_CFLAGS -U_XOPEN_SOURCE" + AC_CHECK_HEADER([apreq.h],, + AC_MSG_ERROR([unable to find a usable libapreq2 header])) + fi + +dnl saved_LIBS="$LIBS" +dnl LIBS="-lapreq $LIBS" +dnl AC_TRY_LINK( +dnl [#include ], +dnl [apreq_param], +dnl [AC_DEFINE(HAVE_APREQ2,1,[Define if apreq2 library was found])], +dnl [AC_MSG_ERROR([unable to link with apreq2]) +dnl ]) +dnl LIBS="$saved_LIBS" + CPPFLAGS="$saved_CPPFLAGS" + + AC_ARG_ENABLE([apxs2-install], + AC_HELP_STRING([--enable-apxs2-install], + [use apxs to install the apache-2 modules]), + APXS2_INSTALL="yes", ) + + + AC_SUBST(APXS2_CFLAGS) + AC_SUBST(APXS2_INCLUDE) + AC_SUBST(APXS2_LIBEXEC) + AC_SUBST(APXS2_SYSCONFDIR) + + # output the Apache 2.0 makefiles + WANT_SUBDIRS="$WANT_SUBDIRS apache-2.0" +fi +# always output the Makefile, even if we don't use it +AC_CONFIG_FILES([apache-2.0/Makefile]) +AM_CONDITIONAL(HAVE_APXS2,test -n "$APXS2") +AM_CONDITIONAL(DO_APXS2_INSTALL,test -n "$APXS2_INSTALL") + + # # Implement the checks of the MySQL Credential Cache # @@ -505,7 +699,7 @@ AC_SUBST(WANT_SUBDIRS) if test -n "$APXS_CC" && test "$APXS_CC" != "$CC" ; then echo "==================================================================" - echo "WARNING: You have chosen to compile Apache modules with a different" + echo "WARNING: You have chosen to compile Apache-1.3 modules with a different" echo " compiler than the one used to compile Apache." echo "" echo " Current compiler: $CC" @@ -515,5 +709,17 @@ if test -n "$APXS_CC" && test "$APXS_CC" != "$CC" ; then echo "==================================================================" fi +if test -n "$APXS2_CC" && test "$APXS2_CC" != "$CC" ; then + echo "==================================================================" + echo "WARNING: You have chosen to compile Apache-2 modules with a different" + echo " compiler than the one used to compile Apache." + echo "" + echo " Current compiler: $CC" + echo " Apache's compiler: $APXS2_CC" + echo "" + echo "This could cause some problems." + echo "==================================================================" +fi + AC_OUTPUT -- 2.1.4