[cpp-sp] branch main updated: Support Boost and STL regex via autoconf.
Scott Cantor
cantor.2 at osu.edu
Fri Dec 20 18:21:24 UTC 2024
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch main
in repository cpp-sp.
View the commit online:
http://git.shibboleth.net/view/?p=cpp-sp.git;a=commit;h=9243faed9ce4ed86ec18e9e6facf634a63e13f7c
The following commit(s) were added to refs/heads/main by this push:
new 9243faed Support Boost and STL regex via autoconf.
9243faed is described below
commit 9243faed9ce4ed86ec18e9e6facf634a63e13f7c
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Fri Dec 20 13:21:19 2024 -0500
Support Boost and STL regex via autoconf.
---
apache/mod_shib_24.cpp | 33 ++++++++++++-----------
configure.ac | 16 +++++++++++
shibsp/config_pub.h.in | 4 +++
shibsp/config_pub_win32.h | 3 +++
shibsp/impl/XMLAccessControl.cpp | 52 +++++++++++++++++++-----------------
shibsp/impl/XMLRequestMapper.cpp | 52 +++++++++++++++++++++---------------
tests/impl/XMLAccessControlTests.cpp | 26 ++++++++++++++++++
7 files changed, 126 insertions(+), 60 deletions(-)
diff --git a/apache/mod_shib_24.cpp b/apache/mod_shib_24.cpp
index 69544ca4..68900c96 100644
--- a/apache/mod_shib_24.cpp
+++ b/apache/mod_shib_24.cpp
@@ -57,14 +57,19 @@
#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>
+#ifdef SHIBSP_USE_BOOST_REGEX
+# include <boost/regex.hpp>
+namespace exp = boost;
+#else
+# include <regex>
+namespace exp = std;
+#endif
// Apache specific header files
#include <httpd.h>
#include <http_config.h>
@@ -89,7 +94,6 @@
using namespace shibsp;
using namespace xmltooling;
using namespace boost::property_tree;
-using namespace boost;
using namespace std;
extern "C" module AP_MODULE_DECLARE_DATA shib_module;
@@ -891,10 +895,10 @@ AccessControl::aclresult_t htAccessControl::doUser(const ShibTargetApache& sta,
if (regexp) {
try {
// TODO: support regex options?
- regex re(w);
- match = regex_match(sta.getRemoteUser(), re);
+ exp::regex re(w, exp::regex_constants::extended);
+ match = exp::regex_match(sta.getRemoteUser(), re, exp::regex_constants::match_any | exp::regex_constants::match_not_null);
}
- catch (const regex_error& e) {
+ catch (const exp::regex_error& e) {
sta.log(SPRequest::SPError,
string("htaccess plugin caught exception while parsing regular expression (") + w + "): " + e.what());
}
@@ -936,11 +940,10 @@ AccessControl::aclresult_t htAccessControl::doAuthnContext(const ShibTargetApach
bool match = false;
if (regexp) {
try {
- // TODO: support regex options?
- regex re(w);
- match = regex_match(ref, re);
+ exp::regex re(w, exp::regex_constants::extended);
+ match = exp::regex_match(ref, re, exp::regex_constants::match_any | exp::regex_constants::match_not_null);
}
- catch (const regex_error& e) {
+ catch (const exp::regex_error& e) {
sta.log(SPRequest::SPError,
string("htaccess plugin caught exception while parsing regular expression (") + w + "): " + e.what());
}
@@ -970,18 +973,18 @@ bool htAccessControl::checkAttribute(const SPRequest& request, const Attribute*
const vector<string>& vals = attr->getSerializedValues();
for (vector<string>::const_iterator v = vals.begin(); v != vals.end(); ++v) {
if (isRegex) {
- regex::flag_type flags = regex_constants::optimize;
+ exp::regex_constants::syntax_option_type flags = exp::regex_constants::extended;
if (!caseSensitive) {
- flags |= regex_constants::icase;
+ flags |= exp::regex_constants::icase;
}
try {
- regex exp(toMatch, flags);
- if (regex_match(*v, exp)) {
+ exp::regex exp(toMatch, flags);
+ if (exp::regex_match(*v, exp, exp::regex_constants::match_any | exp::regex_constants::match_not_null)) {
if (request.isPriorityEnabled(SPRequest::SPDebug))
request.log(SPRequest::SPDebug, string("htaccess: expecting regexp ") + toMatch + ", got " + *v + ": accepted");
return true;
}
- } catch (const regex_error& e) {
+ } catch (const exp::regex_error& e) {
request.log(SPRequest::SPError,
string("htaccess plugin caught exception while parsing regular expression (") + toMatch + "): " + e.what());
}
diff --git a/configure.ac b/configure.ac
index 49f47f06..165298df 100644
--- a/configure.ac
+++ b/configure.ac
@@ -93,6 +93,22 @@ BOOST_STRING_ALGO
BOOST_TEST
BOOST_TUPLE
+## Use Boost for regex?
+AC_ARG_ENABLE([boost-regex],
+ AS_HELP_STRING([--disable-boost-regex],[do not use Boost for regular expression support]),
+ [boostregex_enabled=$enableval], [boostregex_enabled=yes])
+if test "x$boostregex_enabled" = "x" ; then
+ boostregex_enabled=yes
+fi
+AC_MSG_CHECKING(whether to use Boost for regular expressions)
+if test "$boostregex_enabled" = "no" ; then
+ AC_MSG_RESULT(no)
+else
+ AC_MSG_RESULT(yes)
+ BOOST_REGEX
+ AC_DEFINE([SHIBSP_USE_BOOST_REGEX],[1],[Define if using Boost for regular expressions.])
+fi
+
# Thank you Solaris, really.
AC_MSG_CHECKING(for ctime_r)
if test -z "$ac_cv_ctime_args"; then
diff --git a/shibsp/config_pub.h.in b/shibsp/config_pub.h.in
index 4ca01720..cca80859 100644
--- a/shibsp/config_pub.h.in
+++ b/shibsp/config_pub.h.in
@@ -9,3 +9,7 @@
/* Define to 1 if you have the <sys/socket.h> header file. */
#undef SHIBSP_HAVE_SYS_SOCKET_H
+
+/* Define if using Boost for regular expressions. */
+#undef SHIBSP_USE_BOOST_REGEX
+
diff --git a/shibsp/config_pub_win32.h b/shibsp/config_pub_win32.h
index 229b8041..df065e09 100644
--- a/shibsp/config_pub_win32.h
+++ b/shibsp/config_pub_win32.h
@@ -21,3 +21,6 @@
/* define if the compiler supports basic C++17 syntax */
#define HAVE_CXX17 1
+/* Define if using Boost for regular expressions. */
+#define SHIBSP_USE_BOOST_REGEX 1
+
diff --git a/shibsp/impl/XMLAccessControl.cpp b/shibsp/impl/XMLAccessControl.cpp
index cb9051af..410670bf 100644
--- a/shibsp/impl/XMLAccessControl.cpp
+++ b/shibsp/impl/XMLAccessControl.cpp
@@ -32,10 +32,17 @@
#include <algorithm>
#include <memory>
#include <set>
-#include <regex>
#include <boost/algorithm/string.hpp>
#include <boost/property_tree/ptree.hpp>
+#ifdef SHIBSP_USE_BOOST_REGEX
+# include <boost/regex.hpp>
+namespace exp = boost;
+#else
+# include <regex>
+namespace exp = std;
+#endif
+
#ifndef HAVE_STRCASECMP
# define strcasecmp _stricmp
#endif
@@ -70,7 +77,7 @@ namespace {
private:
string m_alias;
string m_exp;
- regex m_re;
+ exp::regex m_re;
};
class Operator : public AccessControl, public NoOpSharedLockable
@@ -168,14 +175,14 @@ AccessControl::aclresult_t Rule::authorized(const SPRequest& request, const Sess
if (m_alias == "valid-user") {
if (session) {
- request.log(SPRequest::SPDebug,"AccessControl plugin accepting valid-user based on active session");
+ request.log(SPRequest::SPDebug,"AccessControl rule accepting valid-user based on active session");
return shib_acl_true;
}
return shib_acl_false;
}
if (m_alias == "user") {
if (m_vals.find(request.getRemoteUser()) != m_vals.end()) {
- request.log(SPRequest::SPDebug, string("AccessControl plugin expecting REMOTE_USER (") + request.getRemoteUser() + "), authz granted");
+ request.log(SPRequest::SPDebug, string("AccessControl rule expecting REMOTE_USER (") + request.getRemoteUser() + "), authz granted");
return shib_acl_true;
}
return shib_acl_false;
@@ -183,7 +190,7 @@ AccessControl::aclresult_t Rule::authorized(const SPRequest& request, const Sess
else if (m_alias == "authnContextClassRef") {
const char* ref = session->getAuthnContextClassRef();
if (ref && m_vals.find(ref) != m_vals.end()) {
- request.log(SPRequest::SPDebug, string("AccessControl plugin expecting authnContextClassRef (") + ref + "), authz granted");
+ request.log(SPRequest::SPDebug, string("AccessControl rule expecting authnContextClassRef (") + ref + "), authz granted");
return shib_acl_true;
}
return shib_acl_false;
@@ -193,11 +200,11 @@ AccessControl::aclresult_t Rule::authorized(const SPRequest& request, const Sess
pair<multimap<string,const Attribute*>::const_iterator, multimap<string,const Attribute*>::const_iterator> attrs =
session->getIndexedAttributes().equal_range(m_alias);
if (attrs.first == attrs.second) {
- request.log(SPRequest::SPWarn, string("rule requires attribute (") + m_alias + "), not found in session");
+ request.log(SPRequest::SPWarn, string("AccessControl rule requires attribute (") + m_alias + "), not found in session");
return shib_acl_false;
}
else if (m_vals.empty()) {
- request.log(SPRequest::SPDebug, string("AccessControl plugin requires presence of attribute (") + m_alias + "), authz granted");
+ request.log(SPRequest::SPDebug, string("AccessControl rule requires presence of attribute (") + m_alias + "), authz granted");
return shib_acl_true;
}
@@ -209,7 +216,7 @@ AccessControl::aclresult_t Rule::authorized(const SPRequest& request, const Sess
for (set<string>::const_iterator i = m_vals.begin(); i != m_vals.end(); ++i) {
for (vector<string>::const_iterator j = vals.begin(); j != vals.end(); ++j) {
if ((caseSensitive && *i == *j) || (!caseSensitive && !strcasecmp(i->c_str(),j->c_str()))) {
- request.log(SPRequest::SPDebug, string("AccessControl plugin expecting (") + *j + "), authz granted");
+ request.log(SPRequest::SPDebug, string("AccessControl rule expecting (") + *j + "), authz granted");
return shib_acl_true;
}
}
@@ -229,24 +236,21 @@ RuleRegex::RuleRegex(const ptree& pt)
static string_to_bool_translator tr;
bool caseSensitive = pt.get(CASE_SENSITIVE_PROP_PATH, true);
try {
- // TODO: more flag options, particular for dialect.
- regex::flag_type flags = regex_constants::optimize;
+ exp::regex_constants::syntax_option_type flags = exp::regex_constants::extended | exp::regex_constants::optimize;
if (!caseSensitive) {
- flags |= regex_constants::icase;
+ flags |= exp::regex_constants::icase;
}
- m_re = regex(m_exp, flags);
+ m_re = exp::regex(m_exp, flags);
}
- catch (const regex_error&) {
+ catch (const exp::regex_error&) {
throw ConfigurationException("Caught exception while parsing RuleRegex regular expression.");
}
}
AccessControl::aclresult_t RuleRegex::authorized(const SPRequest& request, const Session* session) const
{
- // TODO: Have to confirm we want regex_match here vs. regex_search.
- // TODO: Have to consider match_flags as well, particularly against some open issues raised against the Xerces behavior.
- // Map alias in rule to the attribute.
+ static exp::regex_constants::match_flag_type match_flags = exp::regex_constants::match_any | exp::regex_constants::match_not_null;
if (!session) {
request.log(SPRequest::SPWarn, "AccessControl plugin not given a valid session to evaluate, are you using lazy sessions?");
@@ -255,22 +259,22 @@ AccessControl::aclresult_t RuleRegex::authorized(const SPRequest& request, const
if (m_alias == "valid-user") {
if (session) {
- request.log(SPRequest::SPDebug,"AccessControl plugin accepting valid-user based on active session");
+ request.log(SPRequest::SPDebug,"AccessControl rule accepting valid-user based on active session");
return shib_acl_true;
}
return shib_acl_false;
}
if (m_alias == "user") {
- if (regex_match(request.getRemoteUser(), m_re)) {
- request.log(SPRequest::SPDebug, string("AccessControl plugin expecting REMOTE_USER (") + m_exp + "), authz granted");
+ if (exp::regex_match(request.getRemoteUser(), m_re, match_flags)) {
+ request.log(SPRequest::SPDebug, string("AccessControl rule expecting REMOTE_USER regex (") + m_exp + "), authz granted");
return shib_acl_true;
}
return shib_acl_false;
}
else if (m_alias == "authnContextClassRef") {
- if (session->getAuthnContextClassRef() && regex_match(session->getAuthnContextClassRef(), m_re)) {
- request.log(SPRequest::SPDebug, string("AccessControl plugin expecting authnContextClassRef (") + m_exp + "), authz granted");
+ if (session->getAuthnContextClassRef() && exp::regex_match(session->getAuthnContextClassRef(), m_re, match_flags)) {
+ request.log(SPRequest::SPDebug, string("AccessControl rule expecting authnContextClassRef regex (") + m_exp + "), authz granted");
return shib_acl_true;
}
return shib_acl_false;
@@ -279,15 +283,15 @@ AccessControl::aclresult_t RuleRegex::authorized(const SPRequest& request, const
// Find the attribute(s) matching the require rule.
auto attrs = session->getIndexedAttributes().equal_range(m_alias);
if (attrs.first == attrs.second) {
- request.log(SPRequest::SPWarn, string("rule requires attribute (") + m_alias + "), not found in session");
+ request.log(SPRequest::SPWarn, string("AccessControl rule requires attribute (") + m_alias + "), not found in session");
return shib_acl_false;
}
for (; attrs.first != attrs.second; ++attrs.first) {
// Now we have to intersect the attribute's values against the regular expression.
for (const string& v : attrs.first->second->getSerializedValues()) {
- if (regex_match(v, m_re)) {
- request.log(SPRequest::SPDebug, string("AccessControl plugin expecting (") + m_exp + "), authz granted");
+ if (exp::regex_match(v, m_re, match_flags)) {
+ request.log(SPRequest::SPDebug, string("AccessControl rule expecting regex (") + m_exp + "), authz granted");
return shib_acl_true;
}
}
diff --git a/shibsp/impl/XMLRequestMapper.cpp b/shibsp/impl/XMLRequestMapper.cpp
index 4349c2e0..68ccc344 100644
--- a/shibsp/impl/XMLRequestMapper.cpp
+++ b/shibsp/impl/XMLRequestMapper.cpp
@@ -12,7 +12,7 @@
* limitations under the License.
*/
-/** XMLRequestMapper.cpp
+/** impl/XMLRequestMapper.cpp
*
* XML-based RequestMapper implementation.
*/
@@ -33,7 +33,6 @@
#include <algorithm>
#include <memory>
-#include <regex>
#include <tuple>
#include <utility>
#include <boost/property_tree/ptree.hpp>
@@ -41,6 +40,14 @@
#include <boost/tokenizer.hpp>
#include <boost/algorithm/string.hpp>
+#ifdef SHIBSP_USE_BOOST_REGEX
+# include <boost/regex.hpp>
+namespace exp = boost;
+#else
+# include <regex>
+namespace exp = std;
+#endif
+
using namespace shibsp;
using namespace boost::property_tree;
using namespace std;
@@ -75,8 +82,8 @@ namespace {
// This uses shared_ptr to support multiple mappings for a given Override for Host.
// For Path, it's just overhead.
map< string,shared_ptr<Override> > m_map;
- vector< pair< regex,unique_ptr<Override> > > m_regexps;
- vector< tuple< string,boost::optional<regex>,unique_ptr<Override> > > m_queries;
+ vector< pair< exp::regex,unique_ptr<Override> > > m_regexps;
+ vector< tuple< string,boost::optional<exp::regex>,unique_ptr<Override> > > m_queries;
private:
unique_ptr<AccessControl> m_acl;
@@ -134,6 +141,9 @@ namespace {
{
return new XMLRequestMapper(pt);
}
+
+ static exp::regex_constants::match_flag_type match_flags =
+ exp::regex_constants::match_any | exp::regex_constants::match_not_null;
}
void SHIBSP_API shibsp::registerRequestMappers()
@@ -316,15 +326,15 @@ Override::Override(bool unicodeAware, ptree& pt, Category& log, const Override*
try {
// TODO: more flag options, particular for dialect.
- regex::flag_type flags = regex_constants::optimize;
+ exp::regex::flag_type flags = exp::regex_constants::extended | exp::regex_constants::optimize;
if (!getBool("caseSensitive", false)) {
- flags |= regex_constants::icase;
+ flags |= exp::regex_constants::icase;
}
- regex exp(regexpprop, flags);
+ exp::regex exp(regexpprop, flags);
m_regexps.push_back(make_pair(exp, std::move(o)));
log.debug("added <PathRegex> mapping (%s)", regexpprop.c_str());
}
- catch (const regex_error& e) {
+ catch (const exp::regex_error& e) {
log.error("error parsing PathRegex regular expression: %s", e.what());
throw ConfigurationException("Invalid regular expression in PathRegex element.");
}
@@ -341,21 +351,21 @@ Override::Override(bool unicodeAware, ptree& pt, Category& log, const Override*
string regexpprop(getString("regex", ""));
if (regexpprop.empty()) {
- m_queries.push_back(make_tuple(nameprop, boost::optional<regex>(), std::move(o)));
+ m_queries.push_back(make_tuple(nameprop, boost::optional<exp::regex>(), std::move(o)));
}
else {
try {
// TODO: more flag options, particular for dialect.
- regex::flag_type flags = regex_constants::optimize;
+ exp::regex::flag_type flags = exp::regex_constants::extended | exp::regex_constants::optimize;
if (!getBool("caseSensitive", false)) {
- flags |= regex_constants::icase;
+ flags |= exp::regex_constants::icase;
}
- regex exp(regexpprop, flags);
+ exp::regex exp(regexpprop, flags);
- m_queries.push_back(make_tuple(nameprop, boost::optional<regex>(exp), std::move(o)));
+ m_queries.push_back(make_tuple(nameprop, boost::optional<exp::regex>(exp), std::move(o)));
log.debug("added <Query> mapping (%s)", nameprop.c_str());
}
- catch (const regex_error& e) {
+ catch (const exp::regex_error& e) {
log.error("caught exception while parsing Query regular expression: %s", e.what());
throw ConfigurationException("Invalid regular expression in Query element.");
}
@@ -435,7 +445,7 @@ const Override* Override::locate(const HTTPRequest& request) const
// If there's anything left, we try for a regex match on the rest of the path minus the query string.
if (*path) {
for (const auto& re : m_regexps) {
- if (regex_match(path, re.first)) {
+ if (regex_match(path, re.first, match_flags)) {
o = re.second.get();
break;
}
@@ -455,7 +465,7 @@ const Override* Override::locate(const HTTPRequest& request) const
if (get<1>(*q)) {
// We have to match one of the values.
while (vals.first != vals.second) {
- if (regex_match(vals.first->second, get<1>(*q).get())) {
+ if (exp::regex_match(vals.first->second, get<1>(*q).get(), match_flags)) {
o = get<2>(*q).get();
descended = true;
break;
@@ -507,14 +517,14 @@ XMLRequestMapperImpl::XMLRequestMapperImpl(ptree& pt, Category& log)
unique_ptr<Override> o(new Override(m_unicodeAware, child.second, log, this));
try {
- regex::flag_type flags = regex_constants::optimize;
+ exp::regex::flag_type flags = exp::regex_constants::extended | exp::regex_constants::optimize;
if (!getBool("caseSensitive", false)) {
- flags |= regex_constants::icase;
+ flags |= exp::regex_constants::icase;
}
- regex exp(regexprop, flags);
+ exp::regex exp(regexprop, flags);
m_regexps.push_back(make_pair(exp, std::move(o)));
}
- catch (const regex_error& e) {
+ catch (const exp::regex_error& e) {
log.error("caught exception while parsing HostRegex regular expression: %s", e.what());
}
@@ -632,7 +642,7 @@ const Override* XMLRequestMapperImpl::findOverride(const char* vhost, const HTTP
o = i->second.get();
else {
for (const auto& re : m_regexps) {
- if (regex_match(vhost, re.first)) {
+ if (exp::regex_match(vhost, re.first, match_flags)) {
o = re.second.get();
}
}
diff --git a/tests/impl/XMLAccessControlTests.cpp b/tests/impl/XMLAccessControlTests.cpp
index 6c13caef..72f55e46 100644
--- a/tests/impl/XMLAccessControlTests.cpp
+++ b/tests/impl/XMLAccessControlTests.cpp
@@ -260,6 +260,32 @@ BOOST_FIXTURE_TEST_CASE(XMLAccessControl_inline_UserRule, XMLAccessControlFixtur
BOOST_CHECK_EQUAL(acl->authorized(request, &session), AccessControl::shib_acl_true);
}
+/////////////
+// Inline ACL test for user regex rule.
+/////////////
+
+BOOST_FIXTURE_TEST_CASE(XMLAccessControl_inline_UserRegexRule, XMLAccessControlFixture)
+{
+ parse("inline-user-regex-acl.xml");
+ BOOST_CHECK_EQUAL(tree.size(), 1);
+
+ unique_ptr<AccessControl> acl(AgentConfig::getConfig().AccessControlManager.newPlugin(
+ tree.front().second.get<string>("<xmlattr>.type").c_str(), tree.front().second, true));
+
+#ifdef HAVE_CXX14
+ shared_lock locker(*acl);
+#endif
+
+ DummyRequest request;
+ DummySession session;
+
+ request.m_user = "smith";
+ BOOST_CHECK_EQUAL(acl->authorized(request, &session), AccessControl::shib_acl_false);
+
+ request.m_user = "jdoe";
+ BOOST_CHECK_EQUAL(acl->authorized(request, &session), AccessControl::shib_acl_true);
+}
+
/////////////
// Inline ACL test for authnContextClassRef rule.
/////////////
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list