Skip to content

Commit cb28dbb

Browse files
author
Pepa Hajek
committed
Add NACM support
1 parent 0f0c8df commit cb28dbb

File tree

4 files changed

+75
-0
lines changed

4 files changed

+75
-0
lines changed

cffi/cdefs.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,11 @@ int sr_get_event_pipe(sr_subscription_ctx_t *, int *);
221221
int sr_subscription_process_events(sr_subscription_ctx_t *, sr_session_ctx_t *, struct timespec *);
222222
int sr_unsubscribe(sr_subscription_ctx_t *);
223223

224+
int sr_nacm_init(sr_session_ctx_t *, sr_subscr_options_t, sr_subscription_ctx_t **);
225+
int sr_nacm_set_user(sr_session_ctx_t *, const char *);
226+
const char* sr_nacm_get_user(sr_session_ctx_t *);
227+
void sr_nacm_destroy(void);
228+
224229
typedef enum sr_event_e {
225230
SR_EV_UPDATE,
226231
SR_EV_CHANGE,

cffi/source.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <sysrepo.h>
77
#include <sysrepo/version.h>
8+
#include <sysrepo/netconf_acm.h>
89

910
#if (SR_VERSION_MAJOR != 7)
1011
#error "This version of sysrepo bindings only works with libsysrepo.so.7"

sysrepo/session.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class SysrepoSession:
3939
"cdata",
4040
"is_implicit",
4141
"subscriptions",
42+
"nacm_subscription",
4243
)
4344

4445
# begin: general
@@ -52,10 +53,33 @@ def __init__(self, cdata, implicit: bool = False):
5253
self.cdata = cdata
5354
self.is_implicit = implicit
5455
self.subscriptions = []
56+
self.nacm_subscription = None
5557

5658
def __enter__(self) -> "SysrepoSession":
5759
return self
5860

61+
def init_nacm(self, nacm_user: str, no_thread: bool = False) -> None:
62+
"""
63+
Set the NACM user for this session. This is used to determine the effective user
64+
for NACM checks.
65+
66+
:arg nacm_user:
67+
The NACM user name to be set.
68+
:arg no_thread:
69+
If True, no thread will be created for handling NACM subscription meaning.
70+
Default to False.
71+
"""
72+
flags = _subscribe_flags(
73+
no_thread=no_thread,
74+
)
75+
if self.is_implicit:
76+
raise SysrepoUnsupportedError("cannot set NACM for implicit sessions")
77+
78+
sub_p = ffi.new("sr_subscription_ctx_t **")
79+
check_call(lib.sr_nacm_init, self.cdata, flags, sub_p)
80+
check_call(lib.sr_nacm_set_user, self.cdata, str2c(nacm_user))
81+
self.nacm_subscription = sub_p
82+
5983
def __exit__(self, *args, **kwargs) -> None:
6084
self.stop()
6185

@@ -70,6 +94,10 @@ def stop(self) -> None:
7094
return # already stopped
7195
if self.is_implicit:
7296
raise SysrepoUnsupportedError("implicit sessions cannot be stopped")
97+
if self.nacm_subscription is not None:
98+
check_call(lib.sr_unsubscribe, self.nacm_subscription[0])
99+
self.nacm_subscription = None
100+
lib.sr_nacm_destroy()
73101

74102
# clear subscriptions
75103
while self.subscriptions:

tests/test_session.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,3 +206,44 @@ def function_thread_two():
206206

207207
thread_one.join()
208208
thread_two.join()
209+
210+
def test_nacm(self):
211+
with self.conn.start_session("running") as sess:
212+
config = {"conf": {"system": {"hostname": "foobar1"}}}
213+
sess.replace_config(config, "sysrepo-example")
214+
nacm_config = {
215+
"ietf-netconf-acm:nacm": {
216+
"enable-nacm": True,
217+
"read-default": "deny",
218+
"groups": {
219+
"group": [
220+
{"name": "admin", "user-name": ["john"]},
221+
]
222+
},
223+
"rule-list": [
224+
{
225+
"name": "sysrepo-example-permit",
226+
"group": ["admin"],
227+
"rule": [
228+
{
229+
"name": "sysrepo-example-permit-read",
230+
"module-name": "sysrepo-example",
231+
"access-operations": "read",
232+
"action": "permit",
233+
}
234+
],
235+
}
236+
],
237+
}
238+
}
239+
sess.edit_batch(nacm_config, "ietf-netconf-acm", strict=True)
240+
sess.apply_changes()
241+
242+
# read access to sysrepo-example is allowed, but write is not for user 'john'
243+
with self.conn.start_session("running") as sess:
244+
sess.init_nacm("john")
245+
data = sess.get_data("/sysrepo-example:conf")
246+
self.assertEqual(data["conf"]["system"]["hostname"], "foobar1")
247+
with self.assertRaises(sysrepo.SysrepoUnauthorizedError):
248+
sess.set_item("/sysrepo-example:conf/system/hostname", "barfoo1")
249+
sess.apply_changes()

0 commit comments

Comments
 (0)