Options for per-content error handling.
authorcantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Tue, 7 Aug 2007 21:54:19 +0000 (21:54 +0000)
committercantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Tue, 7 Aug 2007 21:54:19 +0000 (21:54 +0000)
Apache command for arbitrary request settings.

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

apache/mod_apache.cpp
apache/mod_shib_20.cpp
apache/mod_shib_22.cpp
schemas/shibboleth-2.0-native-sp-config.xsd
shibsp/ServiceProvider.cpp

index 6b14131..bfa823f 100644 (file)
@@ -141,6 +141,8 @@ extern "C" void* merge_shib_server_config (SH_AP_POOL* p, void* base, void* sub)
 // per-dir module configuration structure
 struct shib_dir_config
 {
+    SH_AP_TABLE* tSettings; // generic table of extensible settings
+
     // RM Configuration
     char* szAuthGrpFile;    // Auth GroupFile name
     int bRequireAll;        // all require directives must match, otherwise OR logic
@@ -161,15 +163,16 @@ struct shib_dir_config
 extern "C" void* create_shib_dir_config (SH_AP_POOL* p, char* d)
 {
     shib_dir_config* dc=(shib_dir_config*)ap_pcalloc(p,sizeof(shib_dir_config));
+    dc->tSettings = NULL;
+    dc->szAuthGrpFile = NULL;
+    dc->bRequireAll = -1;
+    dc->szApplicationId = NULL;
+    dc->szRequireWith = NULL;
+    dc->szRedirectToSSL = NULL;
     dc->bOff = -1;
     dc->bBasicHijack = -1;
     dc->bRequireSession = -1;
     dc->bExportAssertion = -1;
-    dc->bRequireAll = -1;
-    dc->szRedirectToSSL = NULL;
-    dc->szAuthGrpFile = NULL;
-    dc->szApplicationId = NULL;
-    dc->szRequireWith = NULL;
     dc->bUseEnvVars = -1;
     dc->bUseHeaders = -1;
     return dc;
@@ -182,6 +185,17 @@ extern "C" void* merge_shib_dir_config (SH_AP_POOL* p, void* base, void* sub)
     shib_dir_config* parent=(shib_dir_config*)base;
     shib_dir_config* child=(shib_dir_config*)sub;
 
+    // The child supersedes any matching table settings in the parent.
+    dc->tSettings = NULL;
+    if (parent->tSettings)
+        dc->tSettings = ap_copy_table(p, parent->tSettings);
+    if (child->tSettings) {
+        if (dc->tSettings)
+            ap_overlap_tables(dc->tSettings, child->tSettings, AP_OVERLAP_TABLES_SET);
+        else
+            dc->tSettings = ap_copy_table(p, child->tSettings);
+    }
+
     if (child->szAuthGrpFile)
         dc->szAuthGrpFile=ap_pstrdup(p,child->szAuthGrpFile);
     else if (parent->szAuthGrpFile)
@@ -266,6 +280,14 @@ extern "C" const char* shib_ap_set_file_slot(cmd_parms* parms,
   return DECLINE_CMD;
 }
 
+extern "C" const char* shib_table_set(cmd_parms* parms, shib_dir_config* dc, const char* arg1, const char* arg2)
+{
+    if (!dc->tSettings)
+        dc->tSettings = ap_make_table(parms->pool, 4);
+    ap_table_set(dc->tSettings, arg1, arg2);
+    return NULL;
+}
+
 /********************************************************************************/
 // Apache ShibTarget subclass(es) here.
 
@@ -701,10 +723,15 @@ pair<bool,bool> ApacheRequestMapper::getBool(const char* name, const char* ns) c
     const PropertySet* s=reinterpret_cast<const PropertySet*>(m_propsKey->getData());
     if (sta && !ns) {
         // Override Apache-settable boolean properties.
-        if (name && !strcmp(name,"requireSession") && sta->m_dc->bRequireSession==1)
-            return make_pair(true,true);
-        else if (name && !strcmp(name,"exportAssertion") && sta->m_dc->bExportAssertion==1)
-            return make_pair(true,true);
+        if (name && !strcmp(name,"requireSession") && sta->m_dc->bRequireSession != -1)
+            return make_pair(true, sta->m_dc->bRequireSession==1);
+        else if (name && !strcmp(name,"exportAssertion") && sta->m_dc->bExportAssertion != -1)
+            return make_pair(true, sta->m_dc->bExportAssertion==1);
+        else if (sta->m_dc->tSettings) {
+            const char* prop = ap_table_get(sta->m_dc->tSettings, name);
+            if (prop)
+                return make_pair(true, !strcmp(prop, "true") || !strcmp(prop, "1") || !strcmp(prop, "On"));
+        }
     }
     return s ? s->getBool(name,ns) : make_pair(false,false);
 }
@@ -730,6 +757,11 @@ pair<bool,const char*> ApacheRequestMapper::getString(const char* name, const ch
             return pair<bool,const char*>(true,sta->m_dc->szRequireWith);
         else if (name && !strcmp(name,"redirectToSSL") && sta->m_dc->szRedirectToSSL)
             return pair<bool,const char*>(true,sta->m_dc->szRedirectToSSL);
+        else if (sta->m_dc->tSettings) {
+            const char* prop = ap_table_get(sta->m_dc->tSettings, name);
+            if (prop)
+                return make_pair(true, prop);
+        }
     }
     return s ? s->getString(name,ns) : pair<bool,const char*>(false,NULL);
 }
@@ -747,7 +779,12 @@ pair<bool,unsigned int> ApacheRequestMapper::getUnsignedInt(const char* name, co
     if (sta && !ns) {
         // Override Apache-settable int properties.
         if (name && !strcmp(name,"redirectToSSL") && sta->m_dc->szRedirectToSSL)
-            return pair<bool,unsigned int>(true,strtol(sta->m_dc->szRedirectToSSL,NULL,10));
+            return pair<bool,unsigned int>(true, strtol(sta->m_dc->szRedirectToSSL, NULL, 10));
+        else if (sta->m_dc->tSettings) {
+            const char* prop = ap_table_get(sta->m_dc->tSettings, name);
+            if (prop)
+                return make_pair(true, strtol(prop, NULL, 10));
+        }
     }
     return s ? s->getUnsignedInt(name,ns) : pair<bool,unsigned int>(false,0);
 }
@@ -760,6 +797,11 @@ pair<bool,int> ApacheRequestMapper::getInt(const char* name, const char* ns) con
         // Override Apache-settable int properties.
         if (name && !strcmp(name,"redirectToSSL") && sta->m_dc->szRedirectToSSL)
             return pair<bool,int>(true,atoi(sta->m_dc->szRedirectToSSL));
+        else if (sta->m_dc->tSettings) {
+            const char* prop = ap_table_get(sta->m_dc->tSettings, name);
+            if (prop)
+                return make_pair(true, atoi(prop));
+        }
     }
     return s ? s->getInt(name,ns) : pair<bool,int>(false,0);
 }
@@ -1225,6 +1267,9 @@ static command_rec shire_cmds[] = {
    (void *) XtOffsetOf (shib_server_config, szScheme),
    RSRC_CONF, TAKE1, "URL scheme to force into generated URLs for a vhost"},
    
+  {"ShibRequestSetting", (config_fn_t)shib_table_set, NULL,
+   OR_AUTHCFG, TAKE2, "Set arbitrary Shibboleth request property for content"},
+
   {"ShibDisable", (config_fn_t)ap_set_flag_slot,
    (void *) XtOffsetOf (shib_dir_config, bOff),
    OR_AUTHCFG, FLAG, "Disable all Shib module activity here to save processing effort"},
@@ -1282,12 +1327,12 @@ module MODULE_VAR_EXPORT mod_shib = {
     shib_auth_checker,         /* check auth */
     NULL,                      /* check access */
     NULL,                      /* type_checker */
-    shib_fixups,               /* fixups */
+    NULL,//shib_fixups,                /* fixups */
     NULL,                      /* logger */
     NULL,                      /* header parser */
     shib_child_init,           /* child_init */
     shib_child_exit,           /* child_exit */
-    shib_post_read             /* post read-request */
+    NULL//shib_post_read               /* post read-request */
 };
 
 #elif defined(SHIB_APACHE_20) || defined(SHIB_APACHE_22)
@@ -1312,56 +1357,55 @@ extern "C" void shib_register_hooks (apr_pool_t *p)
 
 extern "C" {
 static command_rec shib_cmds[] = {
-  AP_INIT_TAKE1("ShibConfig",
-               (config_fn_t)ap_set_global_string_slot, &g_szSHIBConfig,
-               RSRC_CONF, "Path to shibboleth.xml config file"),
-  AP_INIT_TAKE1("ShibCatalogs",
-     (config_fn_t)ap_set_global_string_slot, &g_szSchemaDir,
-      RSRC_CONF, "Paths of XML schema catalogs"),
-  AP_INIT_TAKE1("ShibSchemaDir",
-     (config_fn_t)ap_set_global_string_slot, &g_szSchemaDir,
-      RSRC_CONF, "Paths of XML schema catalogs (deprecated in favor of ShibCatalogs)"),
-
-  AP_INIT_TAKE1("ShibURLScheme",
-     (config_fn_t)shib_set_server_string_slot,
-     (void *) offsetof (shib_server_config, szScheme),
-      RSRC_CONF, "URL scheme to force into generated URLs for a vhost"),
-
-  AP_INIT_FLAG("ShibDisable", (config_fn_t)ap_set_flag_slot,
+    AP_INIT_TAKE1("ShibConfig", (config_fn_t)ap_set_global_string_slot, &g_szSHIBConfig,
+        RSRC_CONF, "Path to shibboleth.xml config file"),
+    AP_INIT_TAKE1("ShibCatalogs", (config_fn_t)ap_set_global_string_slot, &g_szSchemaDir,
+        RSRC_CONF, "Paths of XML schema catalogs"),
+    AP_INIT_TAKE1("ShibSchemaDir", (config_fn_t)ap_set_global_string_slot, &g_szSchemaDir,
+        RSRC_CONF, "Paths of XML schema catalogs (deprecated in favor of ShibCatalogs)"),
+
+    AP_INIT_TAKE1("ShibURLScheme", (config_fn_t)shib_set_server_string_slot,
+        (void *) offsetof (shib_server_config, szScheme),
+        RSRC_CONF, "URL scheme to force into generated URLs for a vhost"),
+
+    AP_INIT_TAKE2("ShibRequestSetting", (config_fn_t)shib_table_set, NULL,
+        OR_AUTHCFG, "Set arbitrary Shibboleth request property for content"),
+
+    AP_INIT_FLAG("ShibDisable", (config_fn_t)ap_set_flag_slot,
         (void *) offsetof (shib_dir_config, bOff),
         OR_AUTHCFG, "Disable all Shib module activity here to save processing effort"),
-  AP_INIT_TAKE1("ShibApplicationId", (config_fn_t)ap_set_string_slot,
+    AP_INIT_TAKE1("ShibApplicationId", (config_fn_t)ap_set_string_slot,
         (void *) offsetof (shib_dir_config, szApplicationId),
         OR_AUTHCFG, "Set Shibboleth applicationId property for content"),
-  AP_INIT_FLAG("ShibBasicHijack", (config_fn_t)ap_set_flag_slot,
+    AP_INIT_FLAG("ShibBasicHijack", (config_fn_t)ap_set_flag_slot,
         (void *) offsetof (shib_dir_config, bBasicHijack),
         OR_AUTHCFG, "Respond to AuthType Basic and convert to shibboleth"),
-  AP_INIT_FLAG("ShibRequireSession", (config_fn_t)ap_set_flag_slot,
+    AP_INIT_FLAG("ShibRequireSession", (config_fn_t)ap_set_flag_slot,
         (void *) offsetof (shib_dir_config, bRequireSession),
         OR_AUTHCFG, "Initiates a new session if one does not exist"),
-  AP_INIT_TAKE1("ShibRequireSessionWith", (config_fn_t)ap_set_string_slot,
+    AP_INIT_TAKE1("ShibRequireSessionWith", (config_fn_t)ap_set_string_slot,
         (void *) offsetof (shib_dir_config, szRequireWith),
         OR_AUTHCFG, "Initiates a new session if one does not exist using a specific SessionInitiator"),
-  AP_INIT_FLAG("ShibExportAssertion", (config_fn_t)ap_set_flag_slot,
+    AP_INIT_FLAG("ShibExportAssertion", (config_fn_t)ap_set_flag_slot,
         (void *) offsetof (shib_dir_config, bExportAssertion),
         OR_AUTHCFG, "Export SAML attribute assertion(s) to Shib-Attributes header"),
-  AP_INIT_TAKE1("ShibRedirectToSSL", (config_fn_t)ap_set_string_slot,
+    AP_INIT_TAKE1("ShibRedirectToSSL", (config_fn_t)ap_set_string_slot,
         (void *) offsetof (shib_dir_config, szRedirectToSSL),
         OR_AUTHCFG, "Redirect non-SSL requests to designated port"),
-  AP_INIT_TAKE1("AuthGroupFile", (config_fn_t)shib_ap_set_file_slot,
+    AP_INIT_TAKE1("AuthGroupFile", (config_fn_t)shib_ap_set_file_slot,
         (void *) offsetof (shib_dir_config, szAuthGrpFile),
         OR_AUTHCFG, "Text file containing group names and member user IDs"),
-  AP_INIT_FLAG("ShibRequireAll", (config_fn_t)ap_set_flag_slot,
+    AP_INIT_FLAG("ShibRequireAll", (config_fn_t)ap_set_flag_slot,
         (void *) offsetof (shib_dir_config, bRequireAll),
         OR_AUTHCFG, "All require directives must match"),
-  AP_INIT_FLAG("ShibUseEnvironment", (config_fn_t)ap_set_flag_slot,
+    AP_INIT_FLAG("ShibUseEnvironment", (config_fn_t)ap_set_flag_slot,
         (void *) offsetof (shib_dir_config, bUseEnvVars),
         OR_AUTHCFG, "Export attributes using environment variables (default)"),
-  AP_INIT_FLAG("ShibUseHeaders", (config_fn_t)ap_set_flag_slot,
+    AP_INIT_FLAG("ShibUseHeaders", (config_fn_t)ap_set_flag_slot,
         (void *) offsetof (shib_dir_config, bUseHeaders),
         OR_AUTHCFG, "Export attributes using custom HTTP headers"),
 
-  {NULL}
+    {NULL}
 };
 
 module AP_MODULE_DECLARE_DATA mod_shib = {
index 5db15c7..065b24e 100644 (file)
 #define ap_clear_pool apr_pool_clear
 #define ap_destroy_pool apr_pool_destroy
 #define ap_make_table apr_table_make
+#define ap_copy_table apr_table_copy
 #define ap_overlay_tables apr_table_overlay
+#define ap_overlap_tables apr_table_overlap
 #define ap_table_elts apr_table_elts
 #define ap_is_empty_table apr_is_empty_table
-
+#define AP_OVERLAP_TABLES_SET APR_OVERLAP_TABLES_SET
 
 #define ap_send_http_header(r)
 #define ap_hard_timeout(str,r)
index c84cd1b..5cab9e4 100644 (file)
 #define ap_table_setn apr_table_setn
 #define ap_table_unset apr_table_unset
 #define ap_table_set apr_table_set
+#define ap_copy_table apr_table_copy
 #define ap_overlay_tables apr_table_overlay
+#define ap_overlap_tables apr_table_overlap
 #define ap_table_elts apr_table_elts
 #define ap_is_empty_table apr_is_empty_table
 #define ap_clear_pool apr_pool_clear
 #define ap_destroy_pool apr_pool_destroy
 #define ap_make_table apr_table_make
+#define AP_OVERLAP_TABLES_SET APR_OVERLAP_TABLES_SET
 
 #define ap_send_http_header(r)
 #define ap_hard_timeout(str,r)
index 7c8f170..15d340a 100644 (file)
                <attribute name="forceAuthn" type="boolean"/>\r
                <attribute name="authnContextClassRef" type="anyURI"/>\r
                <attribute name="authnContextComparison" type="samlp:AuthnContextComparisonType"/>\r
+               <attribute name="sessionError" type="anyURI"/>\r
+               <attribute name="metadataError" type="anyURI"/>\r
+               <attribute name="accessError" type="anyURI"/>\r
+               <attribute name="sslError" type="anyURI"/>\r
                <anyAttribute namespace="##other" processContents="lax"/>\r
        </attributeGroup>\r
        <element name="AccessControlProvider" type="conf:PluggableType"/>\r
                        </sequence>\r
                        <attribute name="session" type="anyURI" use="required"/>\r
                        <attribute name="metadata" type="anyURI"/>\r
-                       <attribute name="rm" type="anyURI"/>\r
                        <attribute name="access" type="anyURI"/>\r
                        <attribute name="ssl" type="anyURI"/>\r
                        <attribute name="supportContact" type="conf:string"/>\r
index 5af4e4b..c4b70b8 100644 (file)
@@ -61,23 +61,37 @@ namespace shibsp {
         request.setResponseHeader("Expires","01-Jan-1997 12:00:00 GMT");
         request.setResponseHeader("Cache-Control","private,no-store,no-cache");
     
+        // Error templates come from the request's settings or from the Errors property set.
+        pair<bool,const char*> pathname = pair<bool,const char*>(false,NULL);
+        try {
+            RequestMapper::Settings settings = request.getRequestSettings();
+            string pagename(page);
+            pagename += "Error";
+            pathname = settings.first->getString(pagename.c_str());
+        }
+        catch (exception& ex) {
+            request.log(SPRequest::SPError, ex.what());
+        }
+
+        // Nothing for request, so check app properties.
         const PropertySet* props=app ? app->getPropertySet("Errors") : NULL;
-        if (props) {
-            pair<bool,const char*> p=props->getString(page);
-            if (p.first) {
-                ifstream infile(p.second);
-                if (infile) {
-                    tp.setPropertySet(props);
-                    stringstream str;
-                    XMLToolingConfig::getConfig().getTemplateEngine()->run(infile, str, tp, tp.getRichException());
-                    return request.sendResponse(str);
-                }
-            }
-            else if (!strcmp(page,"access")) {
-                istringstream msg("Access Denied");
-                return request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_FORBIDDEN);
+        if (!pathname.first && props)
+            pathname=props->getString(page);
+
+        if (pathname.first) {
+            ifstream infile(pathname.second);
+            if (infile) {
+                tp.setPropertySet(props);
+                stringstream str;
+                XMLToolingConfig::getConfig().getTemplateEngine()->run(infile, str, tp, tp.getRichException());
+                return request.sendResponse(str);
             }
         }
+        
+        if (!strcmp(page,"access")) {
+            istringstream msg("Access Denied");
+            return request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_FORBIDDEN);
+        }
     
         string errstr = string("sendError could not process error template (") + page + ")";
         request.log(SPRequest::SPError, errstr);