First pass at an apache-2 module. It compiles on Linux
authorwarlord <warlord@cb58f699-b61c-0410-a6fe-9272a202ed29>
Tue, 23 Sep 2003 23:58:43 +0000 (23:58 +0000)
committerwarlord <warlord@cb58f699-b61c-0410-a6fe-9272a202ed29>
Tue, 23 Sep 2003 23:58:43 +0000 (23:58 +0000)
but it wont work, yet.

git-svn-id: https://svn.middleware.georgetown.edu/cpp-sp/trunk@703 cb58f699-b61c-0410-a6fe-9272a202ed29

Makefile.am
apache-2.0/.cvsignore [new file with mode: 0644]
apache-2.0/Makefile.am [new file with mode: 0644]
apache-2.0/mod_shib.cpp [new file with mode: 0644]
configure.ac

index eef83e8..a1181cc 100644 (file)
@@ -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/.cvsignore b/apache-2.0/.cvsignore
new file mode 100644 (file)
index 0000000..eddae44
--- /dev/null
@@ -0,0 +1,8 @@
+Makefile.in
+Makefile
+.libs
+.deps
+*.lo
+*.la
+Debug
+*.plg
diff --git a/apache-2.0/Makefile.am b/apache-2.0/Makefile.am
new file mode 100644 (file)
index 0000000..1b6fc49
--- /dev/null
@@ -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 (file)
index 0000000..5094eda
--- /dev/null
@@ -0,0 +1,691 @@
+/*
+ * mod_shib.cpp -- Shibboleth module for Apache-2.0
+ *
+ * Created by: Derek Atkins <derek@ihtfp.com>
+ *
+ * $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_protocol.h>
+#include <http_main.h>
+#include <util_script.h>
+#include <apr_strings.h>
+#define CORE_PRIVATE
+#include <http_core.h>
+#include <http_log.h>
+
+#include <fstream>
+#include <sstream>
+#include <stdexcept>
+
+// For POST processing from Apache
+//-- do we still need this? #undef _XOPEN_SOURCE               // bombs on solaris
+#include <apreq_params.h>
+
+#include <unistd.h>            // 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
index 5aec266..0b83fbe 100644 (file)
@@ -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 <apreq.h>],
+                   [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 <apreq.h>],
+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