[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