[cpp-sp] 02/02: Initial set of tests and fixes for RequestMapper.
Scott Cantor
cantor.2 at osu.edu
Thu Dec 26 17:58:31 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=8e91044bcf63e0cda4dc1152f83f18a590eea560
commit 8e91044bcf63e0cda4dc1152f83f18a590eea560
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Dec 26 12:58:25 2024 -0500
Initial set of tests and fixes for RequestMapper.
---
shibsp/impl/XMLRequestMapper.cpp | 109 ++---
tests/Makefile.am | 1 +
tests/data/impl/console-shibboleth.ini | 1 +
tests/data/impl/reqmap/badxml.xml | 1 +
tests/data/impl/reqmap/external-badxml.xml | 1 +
tests/data/impl/reqmap/inline-no-applicationId.xml | 14 +
.../data/impl/reqmap/inline-with-applicationId.xml | 6 +
tests/data/impl/reqmap/internal-invalid.xml | 3 +
tests/data/impl/reqmap/internal-invalid2.xml | 7 +
tests/impl/XMLRequestMapperTests.cpp | 480 +++++++++++++++++++++
10 files changed, 572 insertions(+), 51 deletions(-)
diff --git a/shibsp/impl/XMLRequestMapper.cpp b/shibsp/impl/XMLRequestMapper.cpp
index 68ccc344..4397a1c9 100644
--- a/shibsp/impl/XMLRequestMapper.cpp
+++ b/shibsp/impl/XMLRequestMapper.cpp
@@ -111,6 +111,8 @@ namespace {
#endif
static const char REQUEST_MAP_PROP_PATH[] = "RequestMap";
+ static const char NAME_PROP_PATH[] = "<xmlattr>.name";
+ static const char REGEX_PROP_PATH[] = "<xmlattr>.regex";
class XMLRequestMapper : public RequestMapper, public ReloadableXMLFile
{
@@ -118,7 +120,7 @@ namespace {
XMLRequestMapper(const ptree& pt)
: ReloadableXMLFile(REQUEST_MAP_PROP_PATH, pt, Category::getInstance(SHIBSP_LOGCAT ".RequestMapper")) {
if (!load().second) {
- throw ConfigurationException("Initial ReqyestMapper configuration was invalid.");
+ throw ConfigurationException("Initial RequestMapper configuration was invalid.");
}
}
@@ -210,9 +212,9 @@ Override::Override(bool unicodeAware, ptree& pt, Category& log, const Override*
: m_unicodeAware(unicodeAware)
{
// Load the <xmlattr> tree as a property set.
- const boost::optional<ptree&> xmlattrs = pt.get_child_optional("<xmlattr>");
- if (xmlattrs) {
- load(xmlattrs.get(), "unset");
+ const boost::optional<ptree&> xmlattr = pt.get_child_optional("<xmlattr>");
+ if (xmlattr) {
+ load(xmlattr.get(), "unset");
}
setParent(base);
@@ -222,14 +224,12 @@ Override::Override(bool unicodeAware, ptree& pt, Category& log, const Override*
static const char PATH_PROP_PATH[] = "Path";
static const char PATH_REGEX_PROP_PATH[] = "PathRegex";
static const char QUERY_PROP_PATH[] = "Query";
- static const char NAME_PROP_PATH[] = "<xmlattr>.name";
- static const char REGEX_PROP_PATH[] = "<xmlattr>.regex";
// Process the various child types.
for (auto& child : pt) {
if (child.first == PATH_PROP_PATH) {
- const string nameprop(getString("name", ""));
+ const string nameprop(child.second.get(NAME_PROP_PATH, ""));
const char* n = nameprop.c_str();
// Skip any leading slashes.
@@ -259,46 +259,43 @@ Override::Override(bool unicodeAware, ptree& pt, Category& log, const Override*
++n;
if (*n) {
- // TODO: Seriously doubt any of this will work, but fixing it will
- // require substantial redesign.
+ // TODO: Tests suggest this is working, but that's extremely hard to
+ // fully believe yet.
// namebuf has the segment to process at "this" level
- // The "new" injected Path Oevrride containing it would have no other
- // attributes since the settings in the slash-containing Path would
- // apply only to the final "leaf" of the Path's directory tree.
+ // The "new" injected Path Oevrride containing it should have no other
+ // attributes since the settings in the slash-containing Path apply
+ // only to the final "leaf" of the Path's directory tree.
// The currently iterated pair's second member is the original Path
// tree with the multi-part pathname and all the settings under <xmlattr>.
- // We would have to make the iterated pair's second member be a tree
+ // We have to make the iterated pair's second member be a tree
// containing the namebuf path segment under <xmlattr>.name and containing
- // the original tree with a modified <xmlattr>.name set to *n under a child named Path.
+ // the original tree with a modified <xmlattr>.name set to *n under a child
+ // named Path.
// Copy the old child tree into a local variable and adjust its name.
ptree old_child(child.second);
old_child.put(NAME_PROP_PATH, n);
- // Create a new tree with just the namebuf prefix and the new child under it.
+ // Create a new tree with just the namebuf prefix and the old child under it.
ptree new_child;
new_child.put(NAME_PROP_PATH, namebuf);
new_child.add_child(PATH_PROP_PATH, old_child);
// Replace the original child iterated with the "new" child.
child.second = new_child;
-
- // Repoint our locals at the new parent.
- n = namebuf.c_str(); // seems like this shouldn't be needed
}
else {
// All we had was a pathname with trailing slash(es), so just reset it without them.
child.second.put(NAME_PROP_PATH, namebuf);
- n = namebuf.c_str(); // seems like this shouldn't be needed
}
}
shared_ptr<Override> o(new Override(m_unicodeAware, child.second, log, this));
string mutable_path = o->getString("name", "");
if (mutable_path.empty()) {
- throw new ConfigurationException("Path element did not contain a name attribute.");
+ throw ConfigurationException("Path element did not contain a name attribute.");
}
// The thinking here is that the Unicode flag tells it to treat the
@@ -327,7 +324,7 @@ Override::Override(bool unicodeAware, ptree& pt, Category& log, const Override*
try {
// TODO: more flag options, particular for dialect.
exp::regex::flag_type flags = exp::regex_constants::extended | exp::regex_constants::optimize;
- if (!getBool("caseSensitive", false)) {
+ if (!o->getBool("caseSensitive", false)) {
flags |= exp::regex_constants::icase;
}
exp::regex exp(regexpprop, flags);
@@ -340,7 +337,7 @@ Override::Override(bool unicodeAware, ptree& pt, Category& log, const Override*
}
}
else if (child.first == QUERY_PROP_PATH) {
- string nameprop(getString("name", ""));
+ string nameprop(child.second.get(NAME_PROP_PATH, ""));
if (nameprop.empty()) {
log.warn("skipping Query element with empty name attribute");
continue;
@@ -348,7 +345,7 @@ Override::Override(bool unicodeAware, ptree& pt, Category& log, const Override*
unique_ptr<Override> o(new Override(m_unicodeAware, child.second, log, this));
- string regexpprop(getString("regex", ""));
+ string regexpprop(o->getString("regex", ""));
if (regexpprop.empty()) {
m_queries.push_back(make_tuple(nameprop, boost::optional<exp::regex>(), std::move(o)));
@@ -357,7 +354,7 @@ Override::Override(bool unicodeAware, ptree& pt, Category& log, const Override*
try {
// TODO: more flag options, particular for dialect.
exp::regex::flag_type flags = exp::regex_constants::extended | exp::regex_constants::optimize;
- if (!getBool("caseSensitive", false)) {
+ if (!o->getBool("caseSensitive", false)) {
flags |= exp::regex_constants::icase;
}
exp::regex exp(regexpprop, flags);
@@ -371,6 +368,9 @@ Override::Override(bool unicodeAware, ptree& pt, Category& log, const Override*
}
}
}
+ else if (child.first != "<xmlattr>") {
+ throw ConfigurationException(string("Unrecognized child element: ") + child.first);
+ }
}
}
@@ -488,29 +488,32 @@ const Override* Override::locate(const HTTPRequest& request) const
XMLRequestMapperImpl::XMLRequestMapperImpl(ptree& pt, Category& log)
{
- // Load the property set.
- load(pt, "unset");
+
+ static const char HOST_PROP_PATH[] = "Host";
+ static const char HOST_REGEX_PROP_PATH[] = "HostRegex";
+ static const char APPLICATION_ID_PROP_PATH[] = "<xmlattr>.applicationId";
// This probably will go away at some point but for now just leaving it.
// Inject "default" app ID if not explicit.
- if (!getString("applicationId")) {
- pt.put("applicationId", "default");
+ const boost::optional<string> appId = pt.get_optional<string>(APPLICATION_ID_PROP_PATH);
+ if (!appId) {
+ pt.put(APPLICATION_ID_PROP_PATH, "default");
}
+ // Load the property set.
+ load(pt.get_child("<xmlattr>"), "unset");
+
// Load any AccessControl provider.
loadACL(pt, log);
m_unicodeAware = getBool("unicodeAware", false);
- static const char HOST_PROP_PATH[] = "Host";
- static const char HOST_REGEX_PROP_PATH[] = "HostRegex";
-
// Loop over the HostRegex elements.
for (auto& child : pt) {
if (child.first == HOST_REGEX_PROP_PATH) {
- string regexprop(getString("regex", ""));
+ string regexprop(child.second.get(REGEX_PROP_PATH, ""));
if (regexprop.empty()) {
- log.warn("Skipping HostRegex element with empty regex attribute");
+ log.warn("skipping HostRegex element with empty regex attribute");
continue;
}
@@ -518,7 +521,7 @@ XMLRequestMapperImpl::XMLRequestMapperImpl(ptree& pt, Category& log)
try {
exp::regex::flag_type flags = exp::regex_constants::extended | exp::regex_constants::optimize;
- if (!getBool("caseSensitive", false)) {
+ if (!o->getBool("caseSensitive", false)) {
flags |= exp::regex_constants::icase;
}
exp::regex exp(regexprop, flags);
@@ -528,12 +531,12 @@ XMLRequestMapperImpl::XMLRequestMapperImpl(ptree& pt, Category& log)
log.error("caught exception while parsing HostRegex regular expression: %s", e.what());
}
- log.debug("Added <HostRegex> mapping for %s", regexprop.c_str());
+ log.debug("added <HostRegex> mapping for %s", regexprop.c_str());
}
else if (child.first == HOST_PROP_PATH) {
- string name(getString("name", ""));
+ string name(child.second.get(NAME_PROP_PATH, ""));
if (name.empty()) {
- log.warn("Skipping Host element with empty name attribute");
+ log.warn("skipping Host element with empty name attribute");
continue;
}
@@ -574,25 +577,25 @@ XMLRequestMapperImpl::XMLRequestMapperImpl(ptree& pt, Category& log)
(!strcmp(scheme,"ldaps") && !strcmp(port,"636"))) {
// First store a port-less version.
if (m_map.count(url)) {
- log.warn("Skipping duplicate Host element (%s)", url.c_str());
+ log.warn("skipping duplicate Host element (%s)", url.c_str());
continue;
}
m_map[url] = o;
- log.debug("Added <Host> mapping for %s", url.c_str());
+ log.debug("added <Host> mapping for %s", url.c_str());
// Now append the port. The shared_ptr should refcount the Override to avoid double deletes.
url=url + ':' + port;
m_map[url] = o;
- log.debug("Added <Host> mapping for %s", url.c_str());
+ log.debug("added <Host> mapping for %s", url.c_str());
}
else {
url=url + ':' + port;
if (m_map.count(url)) {
- log.warn("Skipping duplicate Host element (%s)", url.c_str());
+ log.warn("skipping duplicate Host element (%s)", url.c_str());
continue;
}
m_map[url] = o;
- log.debug("Added <Host> mapping for %s", url.c_str());
+ log.debug("added <Host> mapping for %s", url.c_str());
}
}
else {
@@ -600,37 +603,40 @@ XMLRequestMapperImpl::XMLRequestMapperImpl(ptree& pt, Category& log)
string url("http://");
url += name;
if (m_map.count(url)) {
- log.warn("Skipping duplicate Host element (%s)", url.c_str());
+ log.warn("skipping duplicate Host element (%s)", url.c_str());
continue;
}
m_map[url] = o;
- log.debug("Added <Host> mapping for %s", url.c_str());
+ log.debug("added <Host> mapping for %s", url.c_str());
url += ":80";
if (m_map.count(url)) {
- log.warn("Skipping duplicate Host element (%s)", url.c_str());
+ log.warn("skipping duplicate Host element (%s)", url.c_str());
continue;
}
m_map[url] = o;
- log.debug("Added <Host> mapping for %s", url.c_str());
+ log.debug("added <Host> mapping for %s", url.c_str());
url = "https://" + name;
if (m_map.count(url)) {
- log.warn("Skipping duplicate Host element (%s)", url.c_str());
+ log.warn("skipping duplicate Host element (%s)", url.c_str());
continue;
}
m_map[url] = o;
- log.debug("Added <Host> mapping for %s", url.c_str());
+ log.debug("added <Host> mapping for %s", url.c_str());
url += ":443";
if (m_map.count(url)) {
- log.warn("Skipping duplicate Host element (%s)", url.c_str());
+ log.warn("skipping duplicate Host element (%s)", url.c_str());
continue;
}
m_map[url] = o;
- log.debug("Added <Host> mapping for %s", url.c_str());
+ log.debug("added <Host> mapping for %s", url.c_str());
}
}
+ else if (child.first != "<xmlattr>") {
+ throw ConfigurationException(string("Unrecognized child element: ") + child.first);
+ }
}
}
@@ -638,8 +644,9 @@ const Override* XMLRequestMapperImpl::findOverride(const char* vhost, const HTTP
{
const Override* o = nullptr;
const auto& i = m_map.find(vhost);
- if (i != m_map.end())
+ if (i != m_map.end()) {
o = i->second.get();
+ }
else {
for (const auto& re : m_regexps) {
if (exp::regex_match(vhost, re.first, match_flags)) {
diff --git a/tests/Makefile.am b/tests/Makefile.am
index af4c671d..9ea04263 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -13,6 +13,7 @@ shibsptest_SOURCES = \
AgentTestSuite.cpp \
AgentConfigTests.cpp \
impl/XMLAccessControlTests.cpp \
+ impl/XMLRequestMapperTests.cpp \
util/PropertyTreeTests.cpp \
util/BoostPropertySetTests.cpp \
util/ReloadableXMLFileTests.cpp
diff --git a/tests/data/impl/console-shibboleth.ini b/tests/data/impl/console-shibboleth.ini
index bc3fb129..c92d4b7b 100644
--- a/tests/data/impl/console-shibboleth.ini
+++ b/tests/data/impl/console-shibboleth.ini
@@ -5,4 +5,5 @@ default-level = INFO
[logging-categories]
Shibboleth.AgentConfig = WARN
Shibboleth.AccessControl = DEBUG
+Shibboleth.RequestMapper = DEBUG
Shibboleth.DummyRequest = DEBUG
diff --git a/tests/data/impl/reqmap/badxml.xml b/tests/data/impl/reqmap/badxml.xml
new file mode 100644
index 00000000..0c037505
--- /dev/null
+++ b/tests/data/impl/reqmap/badxml.xml
@@ -0,0 +1 @@
+<RequestMap>
diff --git a/tests/data/impl/reqmap/external-badxml.xml b/tests/data/impl/reqmap/external-badxml.xml
new file mode 100644
index 00000000..6290952c
--- /dev/null
+++ b/tests/data/impl/reqmap/external-badxml.xml
@@ -0,0 +1 @@
+<RequestMapper type="XML" path="./data/impl/reqmap/badxml.xml" />
diff --git a/tests/data/impl/reqmap/inline-no-applicationId.xml b/tests/data/impl/reqmap/inline-no-applicationId.xml
new file mode 100644
index 00000000..3488499c
--- /dev/null
+++ b/tests/data/impl/reqmap/inline-no-applicationId.xml
@@ -0,0 +1,14 @@
+<RequestMapper type="XML">
+ <RequestMap>
+ <Host name="sp.example.org">
+ <Path name="/" />
+ <Path name="secure" requireSession="true">
+ <Query name="foo" entityId="https://idp.example.org/foo" />
+ <Query name="bar" regex="baz" entityId="https://idp.example.org/bar" />
+ </Path>
+ <PathRegex regex="FoLdEr\d" requireSessionWith="custom" />
+ <Path name="foo/bar/baz" forceAuthn="1" />
+ </Host>
+ <HostRegex regex="https\://sp\d\.example\.org\:443" isPassive="1" />
+ </RequestMap>
+</RequestMapper>
diff --git a/tests/data/impl/reqmap/inline-with-applicationId.xml b/tests/data/impl/reqmap/inline-with-applicationId.xml
new file mode 100644
index 00000000..e64a40ce
--- /dev/null
+++ b/tests/data/impl/reqmap/inline-with-applicationId.xml
@@ -0,0 +1,6 @@
+<RequestMapper type="XML">
+ <RequestMap applicationId="custom">
+ <Host name="sp.example.org">
+ </Host>
+ </RequestMap>
+</RequestMapper>
diff --git a/tests/data/impl/reqmap/internal-invalid.xml b/tests/data/impl/reqmap/internal-invalid.xml
new file mode 100644
index 00000000..79668564
--- /dev/null
+++ b/tests/data/impl/reqmap/internal-invalid.xml
@@ -0,0 +1,3 @@
+<RequestMapper type="XML">
+ <RequestMapper/>
+</RequestMapper>
diff --git a/tests/data/impl/reqmap/internal-invalid2.xml b/tests/data/impl/reqmap/internal-invalid2.xml
new file mode 100644
index 00000000..99c10271
--- /dev/null
+++ b/tests/data/impl/reqmap/internal-invalid2.xml
@@ -0,0 +1,7 @@
+<RequestMapper type="XML">
+ <RequestMap>
+ <Host name="sp.example.org">
+ <Foo/>
+ </Host>
+ </RequestMap>
+</RequestMapper>
diff --git a/tests/impl/XMLRequestMapperTests.cpp b/tests/impl/XMLRequestMapperTests.cpp
new file mode 100644
index 00000000..2dcce7e0
--- /dev/null
+++ b/tests/impl/XMLRequestMapperTests.cpp
@@ -0,0 +1,480 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * XMLRequestMapperTests.cpp
+ *
+ * Unit tests for XML RequestMapper implementation.
+ */
+
+#include "exceptions.h"
+#include "AbstractSPRequest.h"
+#include "AccessControl.h"
+#include "AgentConfig.h"
+#include "RequestMapper.h"
+#include "logging/Category.h"
+#include "util/PropertySet.h"
+
+#ifdef HAVE_CXX14
+# include <shared_mutex>
+#endif
+
+#include <boost/test/unit_test.hpp>
+#include <boost/property_tree/xml_parser.hpp>
+
+using namespace shibsp;
+using namespace boost::property_tree;
+using namespace std;
+
+#define DATA_PATH "./data/impl/reqmap/"
+
+namespace {
+
+class DummyRequest : public AbstractSPRequest {
+public:
+ DummyRequest(const char* uri=nullptr) : AbstractSPRequest(SHIBSP_LOGCAT ".DummyRequest") {
+ setRequestURI(uri);
+ }
+ const char* getMethod() const { return nullptr; }
+ const char* getScheme() const { return m_scheme.c_str(); }
+ const char* getHostname() const { return m_hostname.c_str(); }
+ int getPort() const { return m_port; }
+ string getContentType() const { return ""; }
+ long getContentLength() const { return -1; }
+ const char* getQueryString() const { return m_query.c_str(); }
+ const char* getRequestBody() const { return nullptr; }
+ string getHeader(const char*) const { return nullptr; }
+ string getRemoteUser() const { return nullptr; }
+ string getAuthType() const { return nullptr; }
+ long sendResponse(istream&, long status) { return status; }
+ void clearHeader(const char*, const char*) {}
+ void setHeader(const char*, const char*) {}
+ void setRemoteUser(const char*) {}
+ long returnDecline() { return 200; }
+ long returnOK() { return 200; }
+
+ string m_scheme;
+ string m_hostname;
+ int m_port;
+ string m_query;
+};
+
+class exceptionCheck {
+public:
+ exceptionCheck(const string& msg) : m_msg(msg) {}
+ bool check_message(const exception& e) {
+ return m_msg.compare(e.what()) == 0;
+ }
+private:
+ string m_msg;
+};
+
+struct XMLRequestMapperFixture
+{
+ XMLRequestMapperFixture() : data_path(DATA_PATH) {
+ AgentConfig::getConfig().init(nullptr, (data_path + "../console-shibboleth.ini").c_str(), true);
+ }
+ ~XMLRequestMapperFixture() {
+ AgentConfig::getConfig().term();
+ }
+
+ void parse(const string& filename) {
+ xml_parser::read_xml(data_path + filename, tree, xml_parser::no_comments|xml_parser::trim_whitespace);
+ }
+
+ ptree tree;
+ string data_path;
+};
+
+/////////////
+// File pointing to external file that's invalid XML.
+/////////////
+
+BOOST_FIXTURE_TEST_CASE(XMLRequestMapper_external_invalid, XMLRequestMapperFixture)
+{
+ parse("external-badxml.xml");
+ BOOST_CHECK_EQUAL(tree.size(), 1);
+
+ exceptionCheck checker("Initial RequestMapper configuration was invalid.");
+ BOOST_CHECK_EXCEPTION(AgentConfig::getConfig().RequestMapperManager.newPlugin(
+ tree.front().second.get<string>("<xmlattr>.type").c_str(), tree.front().second, true),
+ ConfigurationException, checker.check_message);
+}
+
+/////////////
+// Inline content that has the wrong child element.
+/////////////
+
+BOOST_FIXTURE_TEST_CASE(XMLRequestMapper_inline_invalid, XMLRequestMapperFixture)
+{
+ parse("internal-invalid.xml");
+ BOOST_CHECK_EQUAL(tree.size(), 1);
+
+ exceptionCheck checker("Initial RequestMapper configuration was invalid.");
+ BOOST_CHECK_EXCEPTION(AgentConfig::getConfig().RequestMapperManager.newPlugin(
+ tree.front().second.get<string>("<xmlattr>.type").c_str(), tree.front().second, true),
+ ConfigurationException, checker.check_message);
+}
+
+/////////////
+// Inline content that has a bad internal element.
+/////////////
+
+BOOST_FIXTURE_TEST_CASE(XMLRequestMapper_inline_invalid_internal, XMLRequestMapperFixture)
+{
+ parse("internal-invalid2.xml");
+ BOOST_CHECK_EQUAL(tree.size(), 1);
+
+ exceptionCheck checker("Initial RequestMapper configuration was invalid.");
+ BOOST_CHECK_EXCEPTION(AgentConfig::getConfig().RequestMapperManager.newPlugin(
+ tree.front().second.get<string>("<xmlattr>.type").c_str(), tree.front().second, true),
+ ConfigurationException, checker.check_message);
+}
+
+/////////////
+// Inline test to check for applicationId defaulting.
+/////////////
+
+BOOST_FIXTURE_TEST_CASE(XMLRequestMapper_inline_defaultingId, XMLRequestMapperFixture)
+{
+ parse("inline-no-applicationId.xml");
+ BOOST_CHECK_EQUAL(tree.size(), 1);
+
+ unique_ptr<RequestMapper> mapper(AgentConfig::getConfig().RequestMapperManager.newPlugin(
+ tree.front().second.get<string>("<xmlattr>.type").c_str(), tree.front().second, true));
+
+ DummyRequest request;
+ request.m_scheme = "https";
+ request.m_hostname = "sp.example.org";
+ request.m_port = 443;
+
+#ifdef HAVE_CXX14
+ shared_lock locker(*mapper);
+#endif
+
+ const RequestMapper::Settings settings = mapper->getSettings(request);
+ BOOST_CHECK_EQUAL(settings.second, nullptr);
+ BOOST_CHECK_EQUAL(settings.first->getString("name"), "sp.example.org");
+ BOOST_CHECK_EQUAL(settings.first->getString("applicationId"), "default");
+}
+
+/////////////
+// Inline test to check for applicationId non-defaulting.
+/////////////
+
+BOOST_FIXTURE_TEST_CASE(XMLRequestMapper_inline_customId, XMLRequestMapperFixture)
+{
+ parse("inline-with-applicationId.xml");
+ BOOST_CHECK_EQUAL(tree.size(), 1);
+
+ unique_ptr<RequestMapper> mapper(AgentConfig::getConfig().RequestMapperManager.newPlugin(
+ tree.front().second.get<string>("<xmlattr>.type").c_str(), tree.front().second, true));
+
+ DummyRequest request;
+ request.m_scheme = "https";
+ request.m_hostname = "sp.example.org";
+ request.m_port = 443;
+
+#ifdef HAVE_CXX14
+ shared_lock locker(*mapper);
+#endif
+
+ const RequestMapper::Settings settings = mapper->getSettings(request);
+ BOOST_CHECK_EQUAL(settings.second, nullptr);
+ BOOST_CHECK_EQUAL(settings.first->getString("name"), "sp.example.org");
+ BOOST_CHECK_EQUAL(settings.first->getString("applicationId"), "custom");
+}
+
+/////////////
+// Inline test to check for unsuccessful mapping.
+/////////////
+
+BOOST_FIXTURE_TEST_CASE(XMLRequestMapper_inline_no_mapping, XMLRequestMapperFixture)
+{
+ parse("inline-no-applicationId.xml");
+ BOOST_CHECK_EQUAL(tree.size(), 1);
+
+ unique_ptr<RequestMapper> mapper(AgentConfig::getConfig().RequestMapperManager.newPlugin(
+ tree.front().second.get<string>("<xmlattr>.type").c_str(), tree.front().second, true));
+
+ DummyRequest request;
+ request.m_scheme = "https";
+ request.m_hostname = "sp.example.org";
+ request.m_port = 80;
+
+#ifdef HAVE_CXX14
+ shared_lock locker(*mapper);
+#endif
+
+ const RequestMapper::Settings settings = mapper->getSettings(request);
+ BOOST_CHECK_EQUAL(settings.second, nullptr);
+ BOOST_CHECK_EQUAL(settings.first->getString("applicationId"), "default");
+ BOOST_CHECK_EQUAL(settings.first->getString("name"), nullptr);
+}
+
+/////////////
+// Inline tests to check for HostRegex mapping.
+/////////////
+
+BOOST_FIXTURE_TEST_CASE(XMLRequestMapper_inline_HostRegex_mapping_failed, XMLRequestMapperFixture)
+{
+ parse("inline-no-applicationId.xml");
+ BOOST_CHECK_EQUAL(tree.size(), 1);
+
+ unique_ptr<RequestMapper> mapper(AgentConfig::getConfig().RequestMapperManager.newPlugin(
+ tree.front().second.get<string>("<xmlattr>.type").c_str(), tree.front().second, true));
+
+ DummyRequest request("/secure");
+ request.m_scheme = "https";
+ request.m_hostname = "spa.example.org";
+ request.m_port = 443;
+
+#ifdef HAVE_CXX14
+ shared_lock locker(*mapper);
+#endif
+
+ const RequestMapper::Settings settings = mapper->getSettings(request);
+ BOOST_CHECK_EQUAL(settings.second, nullptr);
+ BOOST_CHECK_EQUAL(settings.first->getString("applicationId"), "default");
+ BOOST_CHECK_EQUAL(settings.first->getString("name"), nullptr);
+ BOOST_CHECK_EQUAL(settings.first->getString("regex"), nullptr);
+ BOOST_CHECK(!settings.first->getBool("requireSession", false));
+ BOOST_CHECK(!settings.first->getBool("isPassive", false));
+}
+
+BOOST_FIXTURE_TEST_CASE(XMLRequestMapper_inline_HostRegex_mapping, XMLRequestMapperFixture)
+{
+ parse("inline-no-applicationId.xml");
+ BOOST_CHECK_EQUAL(tree.size(), 1);
+
+ unique_ptr<RequestMapper> mapper(AgentConfig::getConfig().RequestMapperManager.newPlugin(
+ tree.front().second.get<string>("<xmlattr>.type").c_str(), tree.front().second, true));
+
+ DummyRequest request("/secure");
+ request.m_scheme = "https";
+ request.m_hostname = "sp4.example.org";
+ request.m_port = 443;
+
+#ifdef HAVE_CXX14
+ shared_lock locker(*mapper);
+#endif
+
+ const RequestMapper::Settings settings = mapper->getSettings(request);
+ BOOST_CHECK_EQUAL(settings.second, nullptr);
+ BOOST_CHECK_EQUAL(settings.first->getString("applicationId"), "default");
+ BOOST_CHECK_EQUAL(settings.first->getString("name"), nullptr);
+ BOOST_CHECK_EQUAL(settings.first->getString("regex"), "https\\://sp\\d\\.example\\.org\\:443");
+ BOOST_CHECK(!settings.first->getBool("requireSession", false));
+ BOOST_CHECK(settings.first->getBool("isPassive", false));
+}
+
+/////////////
+// Inline test to check for Path mapping.
+/////////////
+
+BOOST_FIXTURE_TEST_CASE(XMLRequestMapper_inline_Path_mapping, XMLRequestMapperFixture)
+{
+ parse("inline-no-applicationId.xml");
+ BOOST_CHECK_EQUAL(tree.size(), 1);
+
+ unique_ptr<RequestMapper> mapper(AgentConfig::getConfig().RequestMapperManager.newPlugin(
+ tree.front().second.get<string>("<xmlattr>.type").c_str(), tree.front().second, true));
+
+ DummyRequest request("/secure");
+ request.m_scheme = "https";
+ request.m_hostname = "sp.example.org";
+ request.m_port = 443;
+
+#ifdef HAVE_CXX14
+ shared_lock locker(*mapper);
+#endif
+
+ const RequestMapper::Settings settings = mapper->getSettings(request);
+ BOOST_CHECK_EQUAL(settings.second, nullptr);
+ BOOST_CHECK_EQUAL(settings.first->getString("applicationId"), "default");
+ BOOST_CHECK_EQUAL(settings.first->getString("name"), "secure");
+ BOOST_CHECK(settings.first->getBool("requireSession", false));
+ BOOST_CHECK(!settings.first->getBool("forceAuthn", false));
+}
+
+/////////////
+// Inline test to check for nested Path mapping.
+/////////////
+
+BOOST_FIXTURE_TEST_CASE(XMLRequestMapper_inline_nested_Path_mapping, XMLRequestMapperFixture)
+{
+ parse("inline-no-applicationId.xml");
+ BOOST_CHECK_EQUAL(tree.size(), 1);
+
+ unique_ptr<RequestMapper> mapper(AgentConfig::getConfig().RequestMapperManager.newPlugin(
+ tree.front().second.get<string>("<xmlattr>.type").c_str(), tree.front().second, true));
+
+ DummyRequest request("/foo/bar/baz/baf");
+ request.m_scheme = "https";
+ request.m_hostname = "sp.example.org";
+ request.m_port = 443;
+
+#ifdef HAVE_CXX14
+ shared_lock locker(*mapper);
+#endif
+
+ const RequestMapper::Settings settings = mapper->getSettings(request);
+ BOOST_CHECK_EQUAL(settings.second, nullptr);
+ BOOST_CHECK_EQUAL(settings.first->getString("applicationId"), "default");
+ BOOST_CHECK_EQUAL(settings.first->getString("name"), "baz");
+ BOOST_CHECK(!settings.first->getBool("requireSession", false));
+ BOOST_CHECK(settings.first->getBool("forceAuthn", false));
+}
+
+/////////////
+// Inline tests to check for PathRegex mapping behavior.
+/////////////
+
+BOOST_FIXTURE_TEST_CASE(XMLRequestMapper_inline_PathRegex_mapping_failed, XMLRequestMapperFixture)
+{
+ parse("inline-no-applicationId.xml");
+ BOOST_CHECK_EQUAL(tree.size(), 1);
+
+ unique_ptr<RequestMapper> mapper(AgentConfig::getConfig().RequestMapperManager.newPlugin(
+ tree.front().second.get<string>("<xmlattr>.type").c_str(), tree.front().second, true));
+
+ DummyRequest request("/folderx");
+ request.m_scheme = "https";
+ request.m_hostname = "sp.example.org";
+ request.m_port = 443;
+
+#ifdef HAVE_CXX14
+ shared_lock locker(*mapper);
+#endif
+
+ const RequestMapper::Settings settings = mapper->getSettings(request);
+ BOOST_CHECK_EQUAL(settings.second, nullptr);
+ BOOST_CHECK_EQUAL(settings.first->getString("applicationId"), "default");
+ BOOST_CHECK_EQUAL(settings.first->getString("name"), "sp.example.org");
+ BOOST_CHECK_EQUAL(settings.first->getString("regex"), nullptr);
+ BOOST_CHECK(!settings.first->getBool("requireSession", false));
+ BOOST_CHECK_EQUAL(settings.first->getString("requireSessionWith"), nullptr);
+}
+
+BOOST_FIXTURE_TEST_CASE(XMLRequestMapper_inline_PathRegex_mapping, XMLRequestMapperFixture)
+{
+ parse("inline-no-applicationId.xml");
+ BOOST_CHECK_EQUAL(tree.size(), 1);
+
+ unique_ptr<RequestMapper> mapper(AgentConfig::getConfig().RequestMapperManager.newPlugin(
+ tree.front().second.get<string>("<xmlattr>.type").c_str(), tree.front().second, true));
+
+ DummyRequest request("/folder1");
+ request.m_scheme = "https";
+ request.m_hostname = "sp.example.org";
+ request.m_port = 443;
+
+#ifdef HAVE_CXX14
+ shared_lock locker(*mapper);
+#endif
+
+ const RequestMapper::Settings settings = mapper->getSettings(request);
+ BOOST_CHECK_EQUAL(settings.second, nullptr);
+ BOOST_CHECK_EQUAL(settings.first->getString("applicationId"), "default");
+ BOOST_CHECK_EQUAL(settings.first->getString("regex"), "FoLdEr\\d");
+ BOOST_CHECK(!settings.first->getBool("requireSession", false));
+ BOOST_CHECK_EQUAL(settings.first->getString("requireSessionWith"), "custom");
+}
+
+/////////////
+// Inline test to check for Query mapping.
+/////////////
+
+BOOST_FIXTURE_TEST_CASE(XMLRequestMapper_inline_Query_mapping, XMLRequestMapperFixture)
+{
+ parse("inline-no-applicationId.xml");
+ BOOST_CHECK_EQUAL(tree.size(), 1);
+
+ unique_ptr<RequestMapper> mapper(AgentConfig::getConfig().RequestMapperManager.newPlugin(
+ tree.front().second.get<string>("<xmlattr>.type").c_str(), tree.front().second, true));
+
+ DummyRequest request("/secure");
+ request.m_scheme = "https";
+ request.m_hostname = "sp.example.org";
+ request.m_port = 443;
+ request.m_query = "foo=jdoe&bar=baz";
+
+#ifdef HAVE_CXX14
+ shared_lock locker(*mapper);
+#endif
+
+ const RequestMapper::Settings settings = mapper->getSettings(request);
+ BOOST_CHECK_EQUAL(settings.second, nullptr);
+ BOOST_CHECK_EQUAL(settings.first->getString("applicationId"), "default");
+ BOOST_CHECK_EQUAL(settings.first->getString("name"), "foo");
+ BOOST_CHECK(settings.first->getBool("requireSession", false));
+ BOOST_CHECK_EQUAL(settings.first->getString("entityId"), "https://idp.example.org/foo");
+}
+
+/////////////
+// Inline tests to check for Query regex mapping.
+/////////////
+
+BOOST_FIXTURE_TEST_CASE(XMLRequestMapper_inline_Query_regex_mapping_failed, XMLRequestMapperFixture)
+{
+ parse("inline-no-applicationId.xml");
+ BOOST_CHECK_EQUAL(tree.size(), 1);
+
+ unique_ptr<RequestMapper> mapper(AgentConfig::getConfig().RequestMapperManager.newPlugin(
+ tree.front().second.get<string>("<xmlattr>.type").c_str(), tree.front().second, true));
+
+ DummyRequest request("/secure");
+ request.m_scheme = "https";
+ request.m_hostname = "sp.example.org";
+ request.m_port = 443;
+ request.m_query = "baz=jdoe";
+
+#ifdef HAVE_CXX14
+ shared_lock locker(*mapper);
+#endif
+
+ const RequestMapper::Settings settings = mapper->getSettings(request);
+ BOOST_CHECK_EQUAL(settings.second, nullptr);
+ BOOST_CHECK_EQUAL(settings.first->getString("applicationId"), "default");
+ BOOST_CHECK_EQUAL(settings.first->getString("name"), "secure");
+ BOOST_CHECK(settings.first->getBool("requireSession", false));
+ BOOST_CHECK_EQUAL(settings.first->getString("entityId"), nullptr);
+}
+
+BOOST_FIXTURE_TEST_CASE(XMLRequestMapper_inline_Query_regex_mapping, XMLRequestMapperFixture)
+{
+ parse("inline-no-applicationId.xml");
+ BOOST_CHECK_EQUAL(tree.size(), 1);
+
+ unique_ptr<RequestMapper> mapper(AgentConfig::getConfig().RequestMapperManager.newPlugin(
+ tree.front().second.get<string>("<xmlattr>.type").c_str(), tree.front().second, true));
+
+ DummyRequest request("/secure");
+ request.m_scheme = "https";
+ request.m_hostname = "sp.example.org";
+ request.m_port = 443;
+ request.m_query = "baz=jdoe&bar=baz";
+
+#ifdef HAVE_CXX14
+ shared_lock locker(*mapper);
+#endif
+
+ const RequestMapper::Settings settings = mapper->getSettings(request);
+ BOOST_CHECK_EQUAL(settings.second, nullptr);
+ BOOST_CHECK_EQUAL(settings.first->getString("applicationId"), "default");
+ BOOST_CHECK_EQUAL(settings.first->getString("name"), "bar");
+ BOOST_CHECK(settings.first->getBool("requireSession", false));
+ BOOST_CHECK_EQUAL(settings.first->getString("entityId"), "https://idp.example.org/bar");
+}
+};
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list