[cpp-sp] 03/03: Add TimeSinceAuthn tests.

Scott Cantor cantor.2 at osu.edu
Mon Oct 27 18:41:37 UTC 2025


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:
https://git.shibboleth.net/view/?p=cpp-sp.git;a=commit;h=ec2010410245902269ed0acafa85d1d592897bcf

commit ec2010410245902269ed0acafa85d1d592897bcf
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Mon Oct 27 14:41:19 2025 -0400

    Add TimeSinceAuthn tests.
---
 tests/data/impl/acl/time/inline-timesinceauth.xml |   3 +
 tests/impl/TimeAccessControlTests.cpp             | 374 ++++++++++++++++++++++
 2 files changed, 377 insertions(+)

diff --git a/tests/data/impl/acl/time/inline-timesinceauth.xml b/tests/data/impl/acl/time/inline-timesinceauth.xml
new file mode 100644
index 00000000..2b3c69fe
--- /dev/null
+++ b/tests/data/impl/acl/time/inline-timesinceauth.xml
@@ -0,0 +1,3 @@
+<AccessControlProvider type="Time">
+	<TimeSinceAuthn>PT1H</TimeSinceAuthn>
+</AccessControlProvider>
diff --git a/tests/impl/TimeAccessControlTests.cpp b/tests/impl/TimeAccessControlTests.cpp
new file mode 100644
index 00000000..8f1ec50f
--- /dev/null
+++ b/tests/impl/TimeAccessControlTests.cpp
@@ -0,0 +1,374 @@
+/*
+ * 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.
+ */
+
+/**
+ * TimeAccessControlTests.cpp
+ *
+ * Unit tests for Time AccessControl implementation.
+ */
+
+#include "exceptions.h"
+#include "AbstractSPRequest.h"
+#include "AccessControl.h"
+#include "AgentConfig.h"
+#include "logging/Category.h"
+#include "remoting/ddf.h"
+#include "session/SessionCache.h"
+#include "util/BoostPropertySet.h"
+
+#include "DummyRequest.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/acl/time/"
+
+namespace {
+
+/** Open structure for testing manipulation. */
+struct DummySession : public Session, public NoOpBasicLockable {
+public:
+    DummySession() {}
+    ~DummySession() {
+        for (auto& a : m_attributes) {
+            a.second.destroy();
+        }
+    }
+
+    const char* getID() const {
+        return nullptr;
+    }
+    unsigned int getVersion() const {
+        return 1;
+    }
+    const char* getApplicationID() const {
+        return nullptr;
+    }
+    time_t getCreation() const {
+        return 0;
+    }
+    time_t getLastAccess() const {
+        return 0;
+    }
+    const map<string,DDF>& getAttributes() const {
+        return m_attributes;
+    }
+    DDF getOpaqueData() const {
+        return DDF();
+    }
+
+    map<string,DDF> m_attributes;
+};
+
+class MappableDummyRequest : public DummyRequest {
+public:
+    MappableDummyRequest() {}
+    ~MappableDummyRequest() {}
+    RequestMapper::Settings getRequestSettings() const { return make_pair(&m_map, nullptr); }
+
+    BoostPropertySet m_map;
+};
+
+class exceptionCheck {
+public:
+    exceptionCheck(const string& msg) : m_msg(msg) {}
+    bool check_message(const exception& e) {
+        if (m_msg.compare(e.what()) == 0) {
+            return true;
+        }
+        else {
+            cout << "Non-matching message: " << e.what() << endl;
+            return false;
+        }
+    }
+private:
+    string m_msg;
+};
+
+struct TimeAccessControlFixture
+{
+    TimeAccessControlFixture() : data_path(DATA_PATH) {
+        AgentConfig::getConfig().init(nullptr, (data_path + "../../console-agent.ini").c_str(), true);
+    }
+    ~TimeAccessControlFixture() {
+        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 ACL file that's invalid XML.
+/////////////
+
+BOOST_FIXTURE_TEST_CASE(TimeAccessControl_external_invalid, TimeAccessControlFixture)
+{
+    parse("external-acl-badxml.xml");
+    BOOST_CHECK_EQUAL(tree.size(), 1);
+
+    exceptionCheck checker("Initial AccessControl configuration was invalid.");
+    BOOST_CHECK_EXCEPTION(AgentConfig::getConfig().AccessControlManager.newPlugin(
+        tree.front().second.get<string>("<xmlattr>.type").c_str(), tree.front().second, true),
+            ConfigurationException, checker.check_message);
+}
+
+/////////////
+// Inline ACL content that has a bad internal element.
+/////////////
+
+BOOST_FIXTURE_TEST_CASE(TimeAccessControl_inline_invalid_internal, TimeAccessControlFixture)
+{
+    parse("internal-acl-invalid2.xml");
+    BOOST_CHECK_EQUAL(tree.size(), 1);
+
+    exceptionCheck checker("Time-based rule requires element content of the form \"LT|LE|EQ|GE|GT value\".");
+    BOOST_CHECK_EXCEPTION(AgentConfig::getConfig().AccessControlManager.newPlugin(
+        tree.front().second.get<string>("<xmlattr>.type").c_str(), tree.front().second, true),
+            ConfigurationException, checker.check_message);
+}
+
+/////////////
+// Inline ACL test for user rule.
+/////////////
+
+BOOST_FIXTURE_TEST_CASE(TimeAccessControl_inline_TimeSinceAuthn, TimeAccessControlFixture)
+{
+    parse("inline-timesinceauth.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
+
+    MappableDummyRequest request;
+    DummySession session;
+
+    // No attribute available.
+    BOOST_CHECK_EQUAL(acl->authorized(request, &session), AccessControl::shib_acl_false);
+
+    DDF ac("Shib-Authentication-Instant");
+    ac.list();
+    ac.add(DDF(nullptr).longinteger(time(nullptr) - 300));
+    session.m_attributes[ac.name()] = ac;
+    
+    BOOST_CHECK_EQUAL(acl->authorized(request, &session), AccessControl::shib_acl_true);
+
+    ac.first().longinteger(time(nullptr) - 7200);
+    BOOST_CHECK_EQUAL(acl->authorized(request, &session), AccessControl::shib_acl_false);
+}
+
+/*
+
+/////////////
+// 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
+
+    MappableDummyRequest request;
+    DummySession session;
+
+    request.m_user = "smith";
+    BOOST_CHECK_EQUAL(acl->authorized(request, &session), AccessControl::shib_acl_false);
+
+    request.m_user = "extrajdoe";
+    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.
+/////////////
+
+BOOST_FIXTURE_TEST_CASE(XMLAccessControl_inline_ACRule, XMLAccessControlFixture)
+{
+    parse("inline-ac-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
+
+    MappableDummyRequest request;
+    DummySession session;
+
+    DDF ac("Shib-AuthnContext-Class");
+    ac.list();
+    ac.add(DDF(nullptr).string("Foo"));
+    session.m_attributes[ac.name()] = ac;
+
+    BOOST_CHECK_EQUAL(acl->authorized(request, &session), AccessControl::shib_acl_false);
+
+    ac.add(DDF(nullptr).string("urn:oasis:names:tc:SAML:2.0:ac:classes:TimeSyncToken"));
+    BOOST_CHECK_EQUAL(acl->authorized(request, &session), AccessControl::shib_acl_true);
+}
+
+/////////////
+// Inline ACL test for attribute rule.
+/////////////
+
+BOOST_FIXTURE_TEST_CASE(XMLAccessControl_inline_AttrRule, XMLAccessControlFixture)
+{
+    parse("inline-attr-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
+
+    MappableDummyRequest request;
+    DummySession session;
+
+    DDF affiliation("affiliation");
+    affiliation.list();
+    session.m_attributes[affiliation.name()] = affiliation;
+
+    BOOST_CHECK_EQUAL(acl->authorized(request, &session), AccessControl::shib_acl_false);
+
+    affiliation.add(DDF(nullptr).string("staff"));
+    BOOST_CHECK_EQUAL(acl->authorized(request, &session), AccessControl::shib_acl_false);
+
+    affiliation.add(DDF(nullptr).string("student"));
+    BOOST_CHECK_EQUAL(acl->authorized(request, &session), AccessControl::shib_acl_true);
+}
+
+/////////////
+// External ACL test for OR operator
+/////////////
+
+BOOST_FIXTURE_TEST_CASE(XMLAccessControl_external_OR, XMLAccessControlFixture)
+{
+    parse("external-or-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
+
+    MappableDummyRequest request;
+    DummySession session;
+
+    request.m_user = "jdoe";
+    BOOST_CHECK_EQUAL(acl->authorized(request, &session), AccessControl::shib_acl_true);
+
+    request.m_user = "smith";
+    BOOST_CHECK_EQUAL(acl->authorized(request, &session), AccessControl::shib_acl_false);
+
+    DDF affiliation("affiliation");
+    affiliation.list();
+    affiliation.add(DDF(nullptr).string("student"));
+    session.m_attributes[affiliation.name()] = affiliation;
+
+    BOOST_CHECK_EQUAL(acl->authorized(request, &session), AccessControl::shib_acl_true);
+}
+
+/////////////
+// External ACL test for AND operator
+/////////////
+
+BOOST_FIXTURE_TEST_CASE(XMLAccessControl_external_AND, XMLAccessControlFixture)
+{
+    parse("external-and-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
+
+    MappableDummyRequest request;
+    DummySession session;
+
+    request.m_user = "jdoe";
+    BOOST_CHECK_EQUAL(acl->authorized(request, &session), AccessControl::shib_acl_false);
+
+    DDF affiliation("affiliation");
+    affiliation.list();
+    affiliation.add(DDF(nullptr).string("student"));
+    session.m_attributes[affiliation.name()] = affiliation;
+
+    BOOST_CHECK_EQUAL(acl->authorized(request, &session), AccessControl::shib_acl_true);
+}
+
+/////////////
+// External ACL test for NOT operator
+/////////////
+
+BOOST_FIXTURE_TEST_CASE(XMLAccessControl_external_NOT, XMLAccessControlFixture)
+{
+    parse("external-not-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
+
+    MappableDummyRequest request;
+    DummySession session;
+
+    DDF affiliation("affiliation");
+    affiliation.list();
+    session.m_attributes[affiliation.name()] = affiliation;
+
+    BOOST_CHECK_EQUAL(acl->authorized(request, &session), AccessControl::shib_acl_true);
+
+    affiliation.add(DDF(nullptr).string("student"));
+
+    BOOST_CHECK_EQUAL(acl->authorized(request, &session), AccessControl::shib_acl_false);
+}
+*/
+
+};
\ 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