Externalize publically-needed configure macros and fix GSS-related bugs.
[shibboleth/sp.git] / apache / mod_apache.cpp
index 1dbf440..3bc0770 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2001-2010 Internet2
+ *  Copyright 2001-2011 Internet2
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -161,8 +161,7 @@ struct shib_dir_config
     char* szApplicationId;  // Shib applicationId value
     char* szRequireWith;    // require a session using a specific initiator?
     char* szRedirectToSSL;  // redirect non-SSL requests to SSL port
-       char* szAccessControlType;      // type of "external" AccessControl plugin
-       char* szAccessControlPath;  // path to AccessControl content
+       char* szAccessControl;  // path to "external" AccessControl plugin file
     int bOff;               // flat-out disable all Shib processing
     int bBasicHijack;       // activate for AuthType Basic?
     int bRequireSession;    // require a session?
@@ -182,8 +181,7 @@ extern "C" void* create_shib_dir_config (SH_AP_POOL* p, char* d)
     dc->szApplicationId = nullptr;
     dc->szRequireWith = nullptr;
     dc->szRedirectToSSL = nullptr;
-       dc->szAccessControlType = nullptr;
-       dc->szAccessControlPath = nullptr;
+       dc->szAccessControl = nullptr;
     dc->bOff = -1;
     dc->bBasicHijack = -1;
     dc->bRequireSession = -1;
@@ -239,19 +237,12 @@ extern "C" void* merge_shib_dir_config (SH_AP_POOL* p, void* base, void* sub)
     else
         dc->szRedirectToSSL=nullptr;
 
-       if (child->szAccessControlType)
-        dc->szAccessControlType=ap_pstrdup(p,child->szAccessControlType);
-    else if (parent->szAccessControlType)
-        dc->szAccessControlType=ap_pstrdup(p,parent->szAccessControlType);
+       if (child->szAccessControl)
+        dc->szAccessControl=ap_pstrdup(p,child->szAccessControl);
+    else if (parent->szAccessControl)
+        dc->szAccessControl=ap_pstrdup(p,parent->szAccessControl);
     else
-        dc->szAccessControlType=nullptr;
-
-       if (child->szAccessControlPath)
-        dc->szAccessControlPath=ap_pstrdup(p,child->szAccessControlPath);
-    else if (parent->szAccessControlPath)
-        dc->szAccessControlPath=ap_pstrdup(p,parent->szAccessControlPath);
-    else
-        dc->szAccessControlPath=nullptr;
+        dc->szAccessControl=nullptr;
 
     dc->bOff=((child->bOff==-1) ? parent->bOff : child->bOff);
     dc->bBasicHijack=((child->bBasicHijack==-1) ? parent->bBasicHijack : child->bBasicHijack);
@@ -318,16 +309,9 @@ extern "C" const char* shib_table_set(cmd_parms* parms, shib_dir_config* dc, con
     return nullptr;
 }
 
-extern "C" const char* shib_acl_set(cmd_parms* parms, shib_dir_config* dc, const char* arg1, const char* arg2)
-{
-       dc->szAccessControlType = ap_pstrdup(parms->pool, arg1);
-       dc->szAccessControlPath = ap_pstrdup(parms->pool, arg2);
-       return nullptr;
-}
-
 
 class ShibTargetApache : public AbstractSPRequest
-#if defined(HAVE_GSSAPI) && !defined(SHIB_APACHE_13)
+#if defined(SHIBSP_HAVE_GSSAPI) && !defined(SHIB_APACHE_13)
     , public GSSRequest
 #endif
 {
@@ -372,6 +356,9 @@ public:
   const char* getScheme() const {
     return m_sc->szScheme ? m_sc->szScheme : ap_http_method(m_req);
   }
+  bool isSecure() const {
+      return HTTPRequest::isSecure();
+  }
   const char* getHostname() const {
     return ap_get_server_name(m_req);
   }
@@ -467,6 +454,12 @@ public:
 #endif
     return m_body.c_str();
   }
+  const char* getParameter(const char* name) const {
+      return AbstractSPRequest::getParameter(name);
+  }
+  vector<const char*>::size_type getParameters(const char* name, vector<const char*>& values) const {
+      return AbstractSPRequest::getParameters(name, values);
+  }
   void clearHeader(const char* rawname, const char* cginame) {
     if (m_dc->bUseHeaders == 1) {
        // ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(m_req), "shib_clear_header: hdr\n");
@@ -607,7 +600,7 @@ public:
   }
   long returnDecline(void) { return DECLINED; }
   long returnOK(void) { return OK; }
-#if defined(HAVE_GSSAPI) && !defined(SHIB_APACHE_13)
+#if defined(SHIBSP_HAVE_GSSAPI) && !defined(SHIB_APACHE_13)
   gss_ctx_id_t getGSSContext() const {
     gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
     apr_pool_userdata_get((void**)&ctx, g_szGSSContextKey, m_req->pool);
@@ -1039,20 +1032,17 @@ AccessControl::aclresult_t htAccessControl::authorized(const SPRequest& request,
         return shib_acl_indeterminate;  // should never happen
 
        // Check for an "embedded" AccessControl plugin.
-       if (sta->m_dc->szAccessControlType && sta->m_dc->szAccessControlPath) {
-               xercesc::DOMDocument* acldoc = XMLToolingConfig::getConfig().getParser().newDocument();
-               XercesJanitor<xercesc::DOMDocument> docjanitor(acldoc);
-               static XMLCh ACL[] = UNICODE_LITERAL_3(A,C,L);
-               static XMLCh _path[] = UNICODE_LITERAL_4(p,a,t,h);
-               static XMLCh _reloadChanges[] = UNICODE_LITERAL_13(r,e,l,o,a,d,C,h,a,n,g,e,s);
-               static XMLCh _false[] = { xercesc::chDigit_0, xercesc::chNull };
-               xercesc::DOMElement* acldom = acldoc->createElementNS(nullptr, ACL);
-               auto_ptr_XMLCh aclpath(sta->m_dc->szAccessControlPath);
-               acldom->setAttributeNS(nullptr, _path, aclpath.get());
-               acldom->setAttributeNS(nullptr, _reloadChanges, _false);
+       if (sta->m_dc->szAccessControl) {
                aclresult_t result = shib_acl_false;
                try {
-                       auto_ptr<AccessControl> aclplugin(SPConfig::getConfig().AccessControlManager.newPlugin(sta->m_dc->szAccessControlType, acldom));
+            ifstream aclfile(sta->m_dc->szAccessControl);
+            xercesc::DOMDocument* acldoc = XMLToolingConfig::getConfig().getParser().parse(aclfile);
+                   XercesJanitor<xercesc::DOMDocument> docjanitor(acldoc);
+                   static XMLCh _type[] = UNICODE_LITERAL_4(t,y,p,e);
+            string t(XMLHelper::getAttrString(acldoc ? acldoc->getDocumentElement() : nullptr, nullptr, _type));
+            if (t.empty())
+                throw ConfigurationException("Missing type attribute in AccessControl plugin configuration.");
+            auto_ptr<AccessControl> aclplugin(SPConfig::getConfig().AccessControlManager.newPlugin(t.c_str(), acldoc->getDocumentElement()));
                        Locker acllock(aclplugin.get());
                        result = aclplugin->authorized(request, session);
                }
@@ -1076,7 +1066,8 @@ AccessControl::aclresult_t htAccessControl::authorized(const SPRequest& request,
             request.log(SPRequest::SPDebug, "htaccess: embedded AccessControl plugin was unsuccessful but not authoritative, leaving it up to Apache");
             return shib_acl_indeterminate;
         }
-       }
+    }
+
 
     require_line* reqs=(require_line*)reqs_arr->elts;
 
@@ -1099,7 +1090,16 @@ AccessControl::aclresult_t htAccessControl::authorized(const SPRequest& request,
         if (!strcasecmp(w,"shibboleth")) {
             // This is a dummy rule needed because Apache conflates authn and authz.
             // Without some require rule, AuthType is ignored and no check_user hooks run.
-            status = true;  // treat it as an "accepted" rule
+
+            // We evaluate to false if ShibAccessControl is used and ShibRequireAll is off.
+            // This allows actual rules to dictate the result, since ShibAccessControl returned
+            // non-true, and if nothing else is used, access will be denied.
+            if (!sta->m_dc->szAccessControl || sta->m_dc->bRequireAll == 1) {
+                // We evaluate to true, because ShibRequireAll is enabled (so a true is just a no-op)
+                // or because there was no other AccessControl rule in place, so this may be the only
+                // rule in effect.
+                status = true;
+            }
         }
         else if (!strcmp(w,"valid-user") && session) {
             request.log(SPRequest::SPDebug, "htaccess: accepting valid-user based on active session");
@@ -1516,8 +1516,9 @@ static command_rec shire_cmds[] = {
   {"ShibRequestSetting", (config_fn_t)shib_table_set, nullptr,
    OR_AUTHCFG, TAKE2, "Set arbitrary Shibboleth request property for content"},
 
-  {"ShibAccessControl", (config_fn_t)shib_acl_set, nullptr,
-   OR_AUTHCFG, TAKE2, "Set arbitrary Shibboleth access control plugin for content"},
+  {"ShibAccessControl", (config_fn_t)ap_set_string_slot,
+   (void *) XtOffsetOf (shib_dir_config, szAccessControl),
+   OR_AUTHCFG, TAKE1, "Set arbitrary Shibboleth access control plugin for content"},
 
   {"ShibDisable", (config_fn_t)ap_set_flag_slot,
    (void *) XtOffsetOf (shib_dir_config, bOff),
@@ -1634,7 +1635,8 @@ static command_rec shib_cmds[] = {
     AP_INIT_TAKE2("ShibRequestSetting", (config_fn_t)shib_table_set, nullptr,
         OR_AUTHCFG, "Set arbitrary Shibboleth request property for content"),
 
-    AP_INIT_TAKE2("ShibAccessControl", (config_fn_t)shib_acl_set, nullptr,
+    AP_INIT_TAKE1("ShibAccessControl", (config_fn_t)ap_set_string_slot,
+        (void *) offsetof (shib_dir_config, szAccessControl),
         OR_AUTHCFG, "Set arbitrary Shibboleth access control plugin for content"),
 
     AP_INIT_FLAG("ShibDisable", (config_fn_t)ap_set_flag_slot,