mirror of
https://github.com/kernelkit/infix.git
synced 2026-08-01 13:23:01 +02:00
134 lines
5.3 KiB
Diff
134 lines
5.3 KiB
Diff
From ad070266f9347f159874e6b2fa57302385f354e3 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
|
|
Date: Wed, 9 Apr 2025 14:51:31 +0200
|
|
Subject: [PATCH 17/20] wrap sr_nacm_check_operation
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
Organization: Wires
|
|
|
|
Sysrepo provides API function for explicit checking if an operation can
|
|
be authorized on a node. This might come handy if one decides to do NACM
|
|
authorization himself, like we will do in our RESTCONF server.
|
|
|
|
Change-Id: Ida41514a7f03ab120a331363b7f9ed8b69918d88
|
|
Signed-off-by: Mattias Walström <lazzer@gmail.com>
|
|
---
|
|
include/sysrepo-cpp/Session.hpp | 1 +
|
|
src/Session.cpp | 13 ++++++++++
|
|
tests/session.cpp | 46 +++++++++++++++++++++++++++++++++
|
|
tests/test_module.yang | 4 +++
|
|
4 files changed, 64 insertions(+)
|
|
|
|
diff --git a/include/sysrepo-cpp/Session.hpp b/include/sysrepo-cpp/Session.hpp
|
|
index 1c409b8..2112d21 100644
|
|
--- a/include/sysrepo-cpp/Session.hpp
|
|
+++ b/include/sysrepo-cpp/Session.hpp
|
|
@@ -101,6 +101,7 @@ public:
|
|
|
|
void setNacmUser(const std::string& user);
|
|
std::optional<std::string> getNacmUser() const;
|
|
+ bool checkNacmOperation(const libyang::DataNode& node) const;
|
|
[[nodiscard]] Subscription initNacm(
|
|
SubscribeOptions opts = SubscribeOptions::Default,
|
|
ExceptionHandler handler = nullptr,
|
|
diff --git a/src/Session.cpp b/src/Session.cpp
|
|
index 2273c79..ce0dec2 100644
|
|
--- a/src/Session.cpp
|
|
+++ b/src/Session.cpp
|
|
@@ -715,6 +715,19 @@ std::optional<std::string> Session::getNacmUser() const
|
|
return username ? std::make_optional<std::string>(username) : std::nullopt;
|
|
}
|
|
|
|
+/**
|
|
+ * @brief Checks if operation is allowed for current NACM user. Wraps `sr_nacm_check_operation`.
|
|
+ * @return true if the current user is authorized to perform operation on given @p node.
|
|
+ *
|
|
+ * Details on unsuccessfull authorizations can be retrieved via Session::getErrors.
|
|
+ * Note that if the NACM user is not set, `sr_nacm_check_operation` and this function both return true.
|
|
+ */
|
|
+bool Session::checkNacmOperation(const libyang::DataNode& node) const
|
|
+{
|
|
+ auto res = sr_nacm_check_operation(m_sess.get(), libyang::getRawNode(node));
|
|
+ return res == SR_ERR_OK;
|
|
+}
|
|
+
|
|
/**
|
|
* @brief Initializes NACM callbacks.
|
|
*
|
|
diff --git a/tests/session.cpp b/tests/session.cpp
|
|
index 548b371..35dd545 100644
|
|
--- a/tests/session.cpp
|
|
+++ b/tests/session.cpp
|
|
@@ -423,6 +423,52 @@ TEST_CASE("session")
|
|
sysrepo::ErrorWithCode);
|
|
}
|
|
|
|
+ DOCTEST_SUBCASE("Session::checkNacmOperation")
|
|
+ {
|
|
+ auto nacmSub = sess.initNacm();
|
|
+
|
|
+ // check NACM access for RPCs
|
|
+ auto shutdownRPC = sess.getContext().newPath("/test_module:shutdown", std::nullopt);
|
|
+ auto denyAllRPC = sess.getContext().newPath("/test_module:deny-all-rpc", std::nullopt);
|
|
+
|
|
+ // user not set, everything is permitted
|
|
+ REQUIRE(sess.checkNacmOperation(shutdownRPC) == true);
|
|
+ REQUIRE(sess.checkNacmOperation(denyAllRPC) == true);
|
|
+ REQUIRE(sess.getErrors().size() == 0);
|
|
+
|
|
+ sess.setNacmUser("root");
|
|
+ REQUIRE(sess.checkNacmOperation(shutdownRPC) == true);
|
|
+ REQUIRE(sess.checkNacmOperation(denyAllRPC) == true);
|
|
+ REQUIRE(sess.getErrors().size() == 0);
|
|
+
|
|
+ sess.setNacmUser("nobody");
|
|
+ REQUIRE(sess.checkNacmOperation(shutdownRPC) == true);
|
|
+ REQUIRE(sess.checkNacmOperation(denyAllRPC) == false);
|
|
+ REQUIRE(sess.getErrors().size() == 1);
|
|
+ REQUIRE(sess.getErrors().at(0) == sysrepo::ErrorInfo{
|
|
+ .code = sysrepo::ErrorCode::Unauthorized,
|
|
+ .errorMessage = "Executing the operation is denied because \"nobody\" NACM authorization failed.",
|
|
+ });
|
|
+
|
|
+ sess.setNacmUser("root"); // 'nobody' is not authorized to write into this subtree
|
|
+ sess.switchDatastore(sysrepo::Datastore::Running);
|
|
+ sess.setItem("/ietf-netconf-acm:nacm/enable-external-groups", "false");
|
|
+ sess.setItem("/ietf-netconf-acm:nacm/groups/group[name='grp']/user-name[.='nobody']", "");
|
|
+ sess.setItem("/ietf-netconf-acm:nacm/rule-list[name='rule']/group[.='grp']", "");
|
|
+ sess.setItem("/ietf-netconf-acm:nacm/rule-list[name='rule']/rule[name='1']/module-name", "test_module");
|
|
+ sess.setItem("/ietf-netconf-acm:nacm/rule-list[name='rule']/rule[name='1']/access-operations", "*");
|
|
+ sess.setItem("/ietf-netconf-acm:nacm/rule-list[name='rule']/rule[name='1']/action", "deny");
|
|
+ sess.applyChanges();
|
|
+
|
|
+ sess.setNacmUser("root");
|
|
+ REQUIRE(sess.checkNacmOperation(denyAllRPC) == true);
|
|
+ REQUIRE(sess.checkNacmOperation(shutdownRPC) == true);
|
|
+
|
|
+ sess.setNacmUser("nobody");
|
|
+ REQUIRE(sess.checkNacmOperation(denyAllRPC) == false);
|
|
+ REQUIRE(sess.checkNacmOperation(shutdownRPC) == false);
|
|
+ }
|
|
+
|
|
DOCTEST_SUBCASE("Session::getPendingChanges")
|
|
{
|
|
REQUIRE(sess.getPendingChanges() == std::nullopt);
|
|
diff --git a/tests/test_module.yang b/tests/test_module.yang
|
|
index 02c467b..3d6c26d 100644
|
|
--- a/tests/test_module.yang
|
|
+++ b/tests/test_module.yang
|
|
@@ -55,6 +55,10 @@ module test_module {
|
|
rpc noop {
|
|
}
|
|
|
|
+ rpc deny-all-rpc {
|
|
+ nacm:default-deny-all;
|
|
+ }
|
|
+
|
|
rpc shutdown {
|
|
output {
|
|
leaf success {
|
|
--
|
|
2.43.0
|
|
|