[cpp-sp] 02/02: Align Apache module code to latest changes.

Scott Cantor cantor.2 at osu.edu
Fri Dec 13 18:39:33 UTC 2024


This is an automated email from the git hooks/post-receive script.

scantor pushed a commit to branch dev/scott-wip
in repository cpp-sp.

View the commit online:
http://git.shibboleth.net/view/?p=cpp-sp.git;a=commit;h=fd42d8fb37f6488f13e150dc611451151cfa713b

commit fd42d8fb37f6488f13e150dc611451151cfa713b
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Fri Dec 13 13:39:14 2024 -0500

    Align Apache module code to latest changes.
---
 apache/mod_shib_24.cpp | 253 +++++++++++++++++++++++--------------------------
 1 file changed, 118 insertions(+), 135 deletions(-)

diff --git a/apache/mod_shib_24.cpp b/apache/mod_shib_24.cpp
index bea85278..5f46fa00 100644
--- a/apache/mod_shib_24.cpp
+++ b/apache/mod_shib_24.cpp
@@ -39,17 +39,16 @@
 #include <shibsp/exceptions.h>
 #include <shibsp/AbstractSPRequest.h>
 #include <shibsp/AccessControl.h>
+#include <shibsp/AgentConfig.h>
 #include <shibsp/RequestMapper.h>
 #include <shibsp/SPConfig.h>
 #include <shibsp/ServiceProvider.h>
 #include <shibsp/SessionCache.h>
 #include <shibsp/attribute/Attribute.h>
+#include <shibsp/util/Lockable.h>
 
 #include <xercesc/util/XMLUniDefs.hpp>
-#include <xercesc/util/regx/RegularExpression.hpp>
 #include <xmltooling/XMLToolingConfig.h>
-#include <xmltooling/util/ParserPool.h>
-#include <xmltooling/util/Threads.h>
 #include <xmltooling/util/XMLConstants.h>
 #include <xmltooling/util/XMLHelper.h>
 
@@ -63,8 +62,13 @@
 #include <set>
 #include <memory>
 #include <fstream>
+#include <regex>
+#ifdef HAVE_CXX14
+# include <shared_mutex>
+#endif
 #include <stdexcept>
 #include <boost/lexical_cast.hpp>
+#include <boost/property_tree/xml_parser.hpp>
 
 // Apache specific header files
 #include <httpd.h>
@@ -89,10 +93,9 @@
 
 using namespace shibsp;
 using namespace xmltooling;
+using namespace boost::property_tree;
 using namespace boost;
 using namespace std;
-using xercesc::RegularExpression;
-using xercesc::XMLException;
 
 extern "C" module AP_MODULE_DECLARE_DATA shib_module;
 static int* const aplog_module_index = &(shib_module.module_index);
@@ -825,13 +828,11 @@ extern "C" int shib_fixups(request_rec* r)
 // With 2.4+, we have to register individual methods to respond
 // to each require rule we want to handle, and have those call
 // into these methods directly.
-class htAccessControl : virtual public AccessControl
+class htAccessControl : virtual public AccessControl, public NoOpSharedLockable
 {
 public:
     htAccessControl() {}
     ~htAccessControl() {}
-    Lockable* lock() {return this;}
-    void unlock() {}
     aclresult_t authorized(const SPRequest& request, const Session* session) const;
 
     aclresult_t doAccessControl(const ShibTargetApache& sta, const Session* session, const char* plugin) const;
@@ -840,7 +841,7 @@ public:
     aclresult_t doShibAttr(const ShibTargetApache& sta, const Session* session, const char* rule, const char* params) const;
 
 private:
-    bool checkAttribute(const SPRequest& request, const Attribute* attr, const char* toMatch, RegularExpression* re) const;
+    bool checkAttribute(const SPRequest& request, const Attribute* attr, const char* toMatch, bool isRegex=false) const;
 };
 
 AccessControl* htAccessFactory(const xercesc::DOMElement* const &, bool)
@@ -852,21 +853,19 @@ AccessControl::aclresult_t htAccessControl::doAccessControl(const ShibTargetApac
 {
     aclresult_t result = shib_acl_false;
     try {
-        ifstream aclfile(plugin);
-        if (!aclfile)
-            throw ConfigurationException("Unable to open access control file ($1).", params(1, plugin));
-        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));
+        ptree pt;
+        xml_parser::read_xml(plugin, pt, xml_parser::no_comments|xml_parser::trim_whitespace);
+        string t = pt.get("<xmlattr>.type", "");
         if (t.empty())
             throw ConfigurationException("Missing type attribute in AccessControl plugin configuration.");
-        scoped_ptr<AccessControl> aclplugin(SPConfig::getConfig().AccessControlManager.newPlugin(t.c_str(), acldoc->getDocumentElement(), true));
-        Locker acllock(aclplugin.get());
+        unique_ptr<AccessControl> aclplugin(AgentConfig::getConfig().AccessControlManager.newPlugin(t.c_str(), pt, true));
+#ifdef HAVE_CXX14
+        shared_lock<AccessControl> acllock(*aclplugin);
+#endif
         result = aclplugin->authorized(sta, session);
     }
-    catch (std::exception& ex) {
-        sta.log(SPRequest::SPError, ex.what());
+    catch (const xml_parser_error& e) {
+        sta.log(SPRequest::SPError, e.what());
     }
     return result;
 }
@@ -893,16 +892,13 @@ AccessControl::aclresult_t htAccessControl::doUser(const ShibTargetApache& sta,
         bool match = false;
         if (regexp) {
             try {
-                // To do regex matching, we have to convert from UTF-8.
-                auto_arrayptr<XMLCh> trans(fromUTF8(w));
-                RegularExpression re(trans.get());
-                auto_arrayptr<XMLCh> trans2(fromUTF8(sta.getRemoteUser().c_str()));
-                match = re.matches(trans2.get());
+                // TODO: support regex options?
+                regex re(w);
+                match = regex_match(sta.getRemoteUser(), re);
             }
-            catch (XMLException& ex) {
-                auto_ptr_char tmp(ex.getMessage());
+            catch (const regex_error& e) {
                 sta.log(SPRequest::SPError,
-                    string("htaccess plugin caught exception while parsing regular expression (") + w + "): " + tmp.get());
+                    string("htaccess plugin caught exception while parsing regular expression (") + w + "): " + e.what());
             }
         }
         else if (sta.getRemoteUser() == w) {
@@ -942,13 +938,13 @@ AccessControl::aclresult_t htAccessControl::doAuthnContext(const ShibTargetApach
             bool match = false;
             if (regexp) {
                 try {
-                    RegularExpression re(w);
-                    match = re.matches(ref);
+                    // TODO: support regex options?
+                    regex re(w);
+                    match = regex_match(ref, re);
                 }
-                catch (XMLException& ex) {
-                    auto_ptr_char tmp(ex.getMessage());
+                catch (const regex_error& e) {
                     sta.log(SPRequest::SPError,
-                        string("htaccess plugin caught exception while parsing regular expression (") + w + "): " + tmp.get());
+                        string("htaccess plugin caught exception while parsing regular expression (") + w + "): " + e.what());
                 }
             }
             else if (!strcmp(w, ref)) {
@@ -970,17 +966,26 @@ AccessControl::aclresult_t htAccessControl::doAuthnContext(const ShibTargetApach
     return shib_acl_false;
 }
 
-bool htAccessControl::checkAttribute(const SPRequest& request, const Attribute* attr, const char* toMatch, RegularExpression* re) const
+bool htAccessControl::checkAttribute(const SPRequest& request, const Attribute* attr, const char* toMatch, bool isRegex) const
 {
     bool caseSensitive = attr->isCaseSensitive();
     const vector<string>& vals = attr->getSerializedValues();
     for (vector<string>::const_iterator v = vals.begin(); v != vals.end(); ++v) {
-        if (re) {
-            auto_arrayptr<XMLCh> trans(fromUTF8(v->c_str()));
-            if (re->matches(trans.get())) {
-                if (request.isPriorityEnabled(SPRequest::SPDebug))
-                    request.log(SPRequest::SPDebug, string("htaccess: expecting regexp ") + toMatch + ", got " + *v + ": accepted");
-                return true;
+        if (isRegex) {
+            regex::flag_type flags = regex_constants::optimize;
+            if (!caseSensitive) {
+                flags |= regex_constants::icase;
+            }
+            try {
+                regex exp(toMatch, flags);
+                if (regex_match(*v, exp)) {
+                    if (request.isPriorityEnabled(SPRequest::SPDebug))
+                        request.log(SPRequest::SPDebug, string("htaccess: expecting regexp ") + toMatch + ", got " + *v + ": accepted");
+                    return true;
+                }
+            } catch (const regex_error& e) {
+                request.log(SPRequest::SPError,
+                    string("htaccess plugin caught exception while parsing regular expression (") + toMatch + "): " + e.what());
             }
         }
         else if ((caseSensitive && *v == toMatch) || (!caseSensitive && !strcasecmp(v->c_str(), toMatch))) {
@@ -995,7 +1000,9 @@ bool htAccessControl::checkAttribute(const SPRequest& request, const Attribute*
     return false;
 }
 
-AccessControl::aclresult_t htAccessControl::doShibAttr(const ShibTargetApache& sta, const Session* session, const char* rule, const char* params) const
+AccessControl::aclresult_t htAccessControl::doShibAttr(
+    const ShibTargetApache& sta, const Session* session, const char* rule, const char* params
+    ) const
 {
     // Find the attribute(s) matching the require rule.
     pair<multimap<string,const Attribute*>::const_iterator,multimap<string,const Attribute*>::const_iterator> attrs =
@@ -1009,23 +1016,11 @@ AccessControl::aclresult_t htAccessControl::doShibAttr(const ShibTargetApache& s
             continue;
         }
 
-        try {
-            scoped_ptr<RegularExpression> re;
-            if (regexp) {
-                auto_arrayptr<XMLCh> trans(fromUTF8(w));
-                re.reset(new xercesc::RegularExpression(trans.get()));
+        pair<multimap<string,const Attribute*>::const_iterator,multimap<string,const Attribute*>::const_iterator> attrs2(attrs);
+        for (; attrs2.first != attrs2.second; ++attrs2.first) {
+            if (checkAttribute(sta, attrs2.first->second, w, regexp)) {
+                return shib_acl_true;
             }
-                    
-            pair<multimap<string,const Attribute*>::const_iterator,multimap<string,const Attribute*>::const_iterator> attrs2(attrs);
-            for (; attrs2.first != attrs2.second; ++attrs2.first) {
-                if (checkAttribute(sta, attrs2.first->second, w, regexp ? re.get() : nullptr)) {
-                    return shib_acl_true;
-                }
-            }
-        }
-        catch (XMLException& ex) {
-            auto_ptr_char tmp(ex.getMessage());
-            sta.log(SPRequest::SPError, string("htaccess plugin caught exception while parsing regular expression (") + w + "): " + tmp.get());
         }
     }
     return shib_acl_false;
@@ -1037,138 +1032,126 @@ AccessControl::aclresult_t htAccessControl::authorized(const SPRequest& request,
     throw ConfigurationException("Save my walrus!");
 }
 
-class ApacheRequestMapper : public virtual RequestMapper, public virtual PropertySet
+class ApacheRequestMapper : public virtual RequestMapper, public virtual PropertySet2
 {
 public:
-    ApacheRequestMapper(const xercesc::DOMElement* e, bool deprecationSupport=true);
+    ApacheRequestMapper(const ptree& pt, bool deprecationSupport=true);
     ~ApacheRequestMapper() {}
-    Lockable* lock() { return m_mapper->lock(); }
-    void unlock() { m_staKey->setData(nullptr); m_propsKey->setData(nullptr); m_mapper->unlock(); }
+    void lock_shared() { m_mapper->lock_shared(); }
+    bool try_lock_shared() { return m_mapper->try_lock_shared(); }
+    void unlock_shared() { m_sta = nullptr; m_props = nullptr; m_mapper->unlock_shared(); }
     Settings getSettings(const HTTPRequest& request) const;
 
-    const PropertySet* getParent() const { return nullptr; }
-    void setParent(const PropertySet*) {}
-    pair<bool,bool> getBool(const char* name) const;
-    pair<bool,const char*> getString(const char* name) const;
-    pair<bool,unsigned int> getUnsignedInt(const char* name) const;
-    pair<bool,int> getInt(const char* name) const;
-    const PropertySet* getPropertySet(const char* name) const;
+    bool hasProperty(const char* name) const;
+    bool getBool(const char* name, bool defaultValue) const;
+    const char* getString(const char* name, const char* defaultValue=nullptr) const;
+    unsigned int getUnsignedInt(const char* name, unsigned int defaultValue) const;
+    int getInt(const char* name, int defaultValue) const;
 
     const htAccessControl& getHTAccessControl() const { return m_htaccess; }
 
 private:
-    scoped_ptr<RequestMapper> m_mapper;
-    scoped_ptr<ThreadKey> m_staKey,m_propsKey;
+    unique_ptr<RequestMapper> m_mapper;
+    static thread_local const ShibTargetApache* m_sta;
+    static thread_local const PropertySet2* m_props;
     mutable htAccessControl m_htaccess;
 };
 
-RequestMapper* ApacheRequestMapFactory(const xercesc::DOMElement* const & e, bool deprecationSupport)
+RequestMapper* ApacheRequestMapFactory(const ptree& pt, bool deprecationSupport)
 {
-    return new ApacheRequestMapper(e, deprecationSupport);
+    return new ApacheRequestMapper(pt, deprecationSupport);
 }
 
-ApacheRequestMapper::ApacheRequestMapper(const xercesc::DOMElement* e, bool deprecationSupport)
-    : m_mapper(SPConfig::getConfig().RequestMapperManager.newPlugin(XML_REQUEST_MAPPER,e, deprecationSupport)),
-        m_staKey(ThreadKey::create(nullptr)),
-        m_propsKey(ThreadKey::create(nullptr))
+ApacheRequestMapper::ApacheRequestMapper(const ptree& pt, bool deprecationSupport)
+    : m_mapper(AgentConfig::getConfig().RequestMapperManager.newPlugin(XML_REQUEST_MAPPER, pt, deprecationSupport))
 {
 }
 
 RequestMapper::Settings ApacheRequestMapper::getSettings(const HTTPRequest& request) const
 {
     Settings s = m_mapper->getSettings(request);
-    m_staKey->setData((void*)dynamic_cast<const ShibTargetApache*>(&request));
-    m_propsKey->setData((void*)s.first);
-    return pair<const PropertySet*,AccessControl*>(this, s.second);
+    m_sta = dynamic_cast<const ShibTargetApache*>(&request);
+    m_props = s.first;
+    return make_pair(this, s.second);
 }
 
-pair<bool,bool> ApacheRequestMapper::getBool(const char* name) const
+bool ApacheRequestMapper::getBool(const char* name, bool defaultValue) const
 {
-    const ShibTargetApache* sta=reinterpret_cast<const ShibTargetApache*>(m_staKey->getData());
-    const PropertySet* s=reinterpret_cast<const PropertySet*>(m_propsKey->getData());
-    if (sta) {
+    if (m_sta) {
         // Override Apache-settable boolean properties.
-        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 = apr_table_get(sta->m_dc->tSettings, name);
+        if (name && !strcmp(name,"requireSession") && m_sta->m_dc->bRequireSession != -1)
+            return m_sta->m_dc->bRequireSession == 1;
+        else if (name && !strcmp(name,"exportAssertion") && m_sta->m_dc->bExportAssertion != -1)
+            return m_sta->m_dc->bExportAssertion == 1;
+        else if (m_sta->m_dc->tSettings) {
+            const char* prop = apr_table_get(m_sta->m_dc->tSettings, name);
             if (prop)
-                return make_pair(true, !strcmp(prop, "true") || !strcmp(prop, "1") || !strcmp(prop, "On"));
+                return !strcmp(prop, "true") || !strcmp(prop, "1") || !strcmp(prop, "On");
         }
     }
-    return s && (!sta->m_dc->tUnsettings || !apr_table_get(sta->m_dc->tUnsettings, name)) ? s->getBool(name) : make_pair(false,false);
+    return m_props && (!m_sta->m_dc->tUnsettings || !apr_table_get(m_sta->m_dc->tUnsettings, name))
+        ? m_props->getBool(name, defaultValue) : defaultValue;
 }
 
-pair<bool,const char*> ApacheRequestMapper::getString(const char* name) const
+const char* ApacheRequestMapper::getString(const char* name, const char* defaultValue) const
 {
-    const ShibTargetApache* sta=reinterpret_cast<const ShibTargetApache*>(m_staKey->getData());
-    const PropertySet* s=reinterpret_cast<const PropertySet*>(m_propsKey->getData());
-    if (sta) {
+    if (m_sta) {
         // Override Apache-settable string properties.
         if (name && !strcmp(name,"authType")) {
-            const char* auth_type = ap_auth_type(sta->m_req);
+            const char* auth_type = ap_auth_type(m_sta->m_req);
             if (auth_type) {
                 // Check for Basic Hijack
-                if (!strcasecmp(auth_type, "basic") && sta->m_dc->bBasicHijack == 1)
+                if (!strcasecmp(auth_type, "basic") && m_sta->m_dc->bBasicHijack == 1)
                     auth_type = "shibboleth";
-                return make_pair(true, auth_type);
+                return auth_type;
             }
         }
-        else if (name && !strcmp(name,"applicationId") && sta->m_dc->szApplicationId)
-            return pair<bool,const char*>(true,sta->m_dc->szApplicationId);
-        else if (name && !strcmp(name,"requireSessionWith") && sta->m_dc->szRequireWith)
-            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 = apr_table_get(sta->m_dc->tSettings, name);
+        else if (name && !strcmp(name,"applicationId") && m_sta->m_dc->szApplicationId)
+            return m_sta->m_dc->szApplicationId;
+        else if (name && !strcmp(name,"requireSessionWith") && m_sta->m_dc->szRequireWith)
+            return m_sta->m_dc->szRequireWith;
+        else if (name && !strcmp(name,"redirectToSSL") && m_sta->m_dc->szRedirectToSSL)
+            return m_sta->m_dc->szRedirectToSSL;
+        else if (m_sta->m_dc->tSettings) {
+            const char* prop = apr_table_get(m_sta->m_dc->tSettings, name);
             if (prop)
-                return make_pair(true, prop);
+                return prop;
         }
     }
-    return s && (!sta->m_dc->tUnsettings || !apr_table_get(sta->m_dc->tUnsettings, name)) ? s->getString(name) : pair<bool,const char*>(false,nullptr);
+    return m_props && (!m_sta->m_dc->tUnsettings || !apr_table_get(m_sta->m_dc->tUnsettings, name))
+        ? m_props->getString(name, defaultValue) : defaultValue;
 }
 
-pair<bool,unsigned int> ApacheRequestMapper::getUnsignedInt(const char* name) const
+unsigned int ApacheRequestMapper::getUnsignedInt(const char* name, unsigned int defaultValue) const
 {
-    const ShibTargetApache* sta=reinterpret_cast<const ShibTargetApache*>(m_staKey->getData());
-    const PropertySet* s=reinterpret_cast<const PropertySet*>(m_propsKey->getData());
-    if (sta) {
+    if (m_sta) {
         // 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, nullptr, 10));
-        else if (sta->m_dc->tSettings) {
-            const char* prop = apr_table_get(sta->m_dc->tSettings, name);
+        if (name && !strcmp(name,"redirectToSSL") && m_sta->m_dc->szRedirectToSSL)
+            return atoi(m_sta->m_dc->szRedirectToSSL);
+        else if (m_sta->m_dc->tSettings) {
+            const char* prop = apr_table_get(m_sta->m_dc->tSettings, name);
             if (prop)
-                return pair<bool,unsigned int>(true, atoi(prop));
+                return atoi(prop);
         }
     }
-    return s && (!sta->m_dc->tUnsettings || !apr_table_get(sta->m_dc->tUnsettings, name)) ? s->getUnsignedInt(name) : pair<bool,unsigned int>(false,0);
+    return m_props && (!m_sta->m_dc->tUnsettings || !apr_table_get(m_sta->m_dc->tUnsettings, name))
+        ? m_props->getUnsignedInt(name, defaultValue) : defaultValue;
 }
 
-pair<bool,int> ApacheRequestMapper::getInt(const char* name) const
+int ApacheRequestMapper::getInt(const char* name, int defaultValue) const
 {
-    const ShibTargetApache* sta=reinterpret_cast<const ShibTargetApache*>(m_staKey->getData());
-    const PropertySet* s=reinterpret_cast<const PropertySet*>(m_propsKey->getData());
-    if (sta) {
+    if (m_sta) {
         // 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 = apr_table_get(sta->m_dc->tSettings, name);
+        if (name && !strcmp(name,"redirectToSSL") && m_sta->m_dc->szRedirectToSSL)
+            return atoi(m_sta->m_dc->szRedirectToSSL);
+        else if (m_sta->m_dc->tSettings) {
+            const char* prop = apr_table_get(m_sta->m_dc->tSettings, name);
             if (prop)
-                return make_pair(true, atoi(prop));
+                return atoi(prop);
         }
     }
-    return s && (!sta->m_dc->tUnsettings || !apr_table_get(sta->m_dc->tUnsettings, name)) ? s->getInt(name) : pair<bool,int>(false,0);
-}
-
-const PropertySet* ApacheRequestMapper::getPropertySet(const char* name) const
-{
-    const PropertySet* s=reinterpret_cast<const PropertySet*>(m_propsKey->getData());
-    return s ? s->getPropertySet(name) : nullptr;
+    return m_props && (!m_sta->m_dc->tUnsettings || !apr_table_get(m_sta->m_dc->tUnsettings, name))
+        ? m_props->getInt(name, defaultValue) : defaultValue;
 }
 
 // Authz callbacks for Apache 2.4
@@ -1478,7 +1461,7 @@ apr_status_t shib_post_config(apr_pool_t* p, apr_pool_t*, apr_pool_t*, server_re
         return !OK;
     }
 
-    g_Config->RequestMapperManager.registerFactory(NATIVE_REQUEST_MAPPER, &ApacheRequestMapFactory);
+    AgentConfig::getConfig().RequestMapperManager.registerFactory(NATIVE_REQUEST_MAPPER, &ApacheRequestMapFactory);
 
     // Set the cleanup handler, passing in the server_rec for logging.
     apr_pool_cleanup_register(p, s, &shib_exit, apr_pool_cleanup_null);

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list