NACM module access control point for edit-config

This commit is contained in:
Olof hagsand 2019-02-01 14:56:45 +01:00
parent ef86cda2fe
commit 8bf5cb0de5
9 changed files with 237 additions and 374 deletions

View file

@ -78,9 +78,9 @@
* CLICON_YANG_MAIN_DIR Provides a directory where all yang modules should be loaded.
* NACM extension (RFC8341)
* NACM Data node READ and WRITE access module support (RFC8341 3.4.5)
* Access control points added for `get` and `get-config` in addition to incoming rpc.
* Access control points added for `get`, `get-config`, `edit-config` in addition to incoming rpc.
* RFC 8341 Example A.2 implemented, see: [test/test_nacm_module.sh]
* Remaining work: data-node PATH
* Remaining work: data-node PATH
* Recovery user "_nacm_recovery" added.
* Example use is restconf PUT when NACM edit-config is permitted, then automatic commit and discard are permitted using recovery user.

View file

@ -601,6 +601,9 @@ text_get(xmldb_handle xh,
* @param[in] x0p Parent of x0
* @param[in] x1 xml tree which modifies base
* @param[in] op OP_MERGE, OP_REPLACE, OP_REMOVE, etc
* @param[in] username User name of requestor for nacm
* @param[in] xnacm NACM XML tree
* @param[in] permit If set, NACM has permitted this tree on an upper level
* @param[out] cbret Initialized cligen buffer. Contains return XML if retval is 0.
* @retval -1 Error
* @retval 0 Failed (cbret set)
@ -617,6 +620,7 @@ text_modify(struct text_handle *th,
enum operation_type op,
char *username,
cxobj *xnacm,
int permit,
cbuf *cbret)
{
int retval = -1;
@ -655,6 +659,13 @@ text_modify(struct text_handle *th,
case OP_MERGE:
case OP_REPLACE:
if (x0==NULL){
if ((op != OP_NONE) && !permit && xnacm){
if ((ret = nacm_datanode_write(NULL, x1, NACM_CREATE, username, xnacm, cbret)) < 0)
goto done;
if (ret == 0)
goto fail;
permit = 1;
}
// int iamkey=0;
if ((x0 = xml_new(x1name, x0p, (yang_stmt*)y0)) == NULL)
goto done;
@ -681,25 +692,13 @@ text_modify(struct text_handle *th,
}
}
if (x1bstr){
if ((x0b = xml_body_get(x0)) == NULL){
if (xnacm){
if ((ret = nacm_datanode_write(NULL, x0, NACM_CREATE, username, xnacm, cbret)) < 0)
goto done;
if (ret == 0)
goto fail;
}
if ((x0b = xml_new("body", x0, NULL)) == NULL)
goto done;
xml_type_set(x0b, CX_BODY);
if (xml_value_set(x0b, x1bstr) < 0)
goto done;
}
else{
if ((x0b = xml_body_get(x0)) != NULL){
x0bstr = xml_value(x0b);
if (x0bstr==NULL || strcmp(x0bstr, x1bstr)){
if (xnacm){
if ((ret = nacm_datanode_write(NULL, x0, NACM_UPDATE, username, xnacm, cbret)) < 0)
if ((op != OP_NONE) && !permit && xnacm){
if ((ret = nacm_datanode_write(NULL, x1,
x0bstr==NULL?NACM_CREATE:NACM_UPDATE,
username, xnacm, cbret)) < 0)
goto done;
if (ret == 0)
goto fail;
@ -708,7 +707,6 @@ text_modify(struct text_handle *th,
goto done;
}
}
}
break;
case OP_DELETE:
@ -719,7 +717,14 @@ text_modify(struct text_handle *th,
}
case OP_REMOVE: /* fall thru */
if (x0){
xml_purge(x0);
if ((op != OP_NONE) && !permit && xnacm){
if ((ret = nacm_datanode_write(NULL, x0, NACM_DELETE, username, xnacm, cbret)) < 0)
goto done;
if (ret == 0)
goto fail;
}
if (xml_purge(x0) < 0)
goto done;
}
break;
default:
@ -735,6 +740,13 @@ text_modify(struct text_handle *th,
goto fail;
}
case OP_REPLACE: /* fall thru */
if (xnacm && !permit){
if ((ret = nacm_datanode_write(NULL, x1, x0?NACM_UPDATE:NACM_CREATE, username, xnacm, cbret)) < 0)
goto done;
if (ret == 0)
goto fail;
permit = 1;
}
if (x0){
xml_purge(x0);
x0 = NULL;
@ -742,10 +754,21 @@ text_modify(struct text_handle *th,
case OP_MERGE: /* fall thru */
case OP_NONE:
/* Special case: anyxml, just replace tree,
See 7.10.3 of RFC6020bis */
See rfc6020 7.10.3:n
An anyxml node is treated as an opaque chunk of data. This data
can be modified in its entirety only.
Any "operation" attributes present on subelements of an anyxml
node are ignored by the NETCONF server.*/
if (y0->yn_keyword == Y_ANYXML){
if (op == OP_NONE)
break;
if (xnacm && op==OP_MERGE && !permit){
if ((ret = nacm_datanode_write(NULL, x0, x0?NACM_UPDATE:NACM_CREATE, username, xnacm, cbret)) < 0)
goto done;
if (ret == 0)
goto fail;
permit = 1;
}
if (x0){
xml_purge(x0);
}
@ -756,6 +779,13 @@ text_modify(struct text_handle *th,
break;
}
if (x0==NULL){
if (xnacm && op==OP_MERGE && !permit){
if ((ret = nacm_datanode_write(NULL, x0, x0?NACM_UPDATE:NACM_CREATE, username, xnacm, cbret)) < 0)
goto done;
if (ret == 0)
goto fail;
permit = 1;
}
if ((x0 = xml_new(x1name, x0p, (yang_stmt*)y0)) == NULL)
goto done;
/* Copy xmlns attributes */
@ -809,7 +839,7 @@ text_modify(struct text_handle *th,
x0c = x0vec[i++];
yc = yang_find_datanode(y0, x1cname);
if ((ret = text_modify(th, x0c, (yang_node*)yc, x0, x1c, op,
username, xnacm, cbret)) < 0)
username, xnacm, permit, cbret)) < 0)
goto done;
/* If xml return - ie netconf error xml tree, then stop and return OK */
if (ret == 0)
@ -823,8 +853,16 @@ text_modify(struct text_handle *th,
goto fail;
}
case OP_REMOVE: /* fall thru */
if (x0)
xml_purge(x0);
if (x0){
if (xnacm){
if ((ret = nacm_datanode_write(NULL, x0, NACM_DELETE, username, xnacm, cbret)) < 0)
goto done;
if (ret == 0)
goto fail;
}
if (xml_purge(x0) < 0)
goto done;
}
break;
default:
break;
@ -847,6 +885,8 @@ text_modify(struct text_handle *th,
* @param[in] x1 xml tree which modifies base
* @param[in] yspec Top-level yang spec (if y is NULL)
* @param[in] op OP_MERGE, OP_REPLACE, OP_REMOVE, etc
* @param[in] username User name of requestor for nacm
* @param[in] xnacm NACM XML tree
* @param[out] cbret Initialized cligen buffer. Contains return XML if retval is 0.
* @retval -1 Error
* @retval 0 Failed (cbret set)
@ -871,6 +911,7 @@ text_modify_top(struct text_handle *th,
yang_stmt *ymod;/* yang module */
char *opstr;
int ret;
int permit = 0;
/* Assure top-levels are 'config' */
assert(x0 && strcmp(xml_name(x0),"config")==0);
@ -881,39 +922,56 @@ text_modify_top(struct text_handle *th,
if (xml_operation(opstr, &op) < 0)
goto done;
/* Special case if x1 is empty, top-level only <config/> */
if (xml_child_nr(x1) == 0){
if (xml_child_nr(x0)) /* base tree not empty */
if (xml_child_nr_type(x1, CX_ELMNT) == 0){
if (xml_child_nr_type(x0, CX_ELMNT)){ /* base tree not empty */
switch(op){
case OP_DELETE:
case OP_REMOVE:
case OP_REPLACE:
if ((ret = nacm_datanode_write(NULL, x0, NACM_DELETE, username, xnacm, cbret)) < 0) /* XXX */
goto done;
if (ret == 0)
goto fail;
x0c = NULL;
while ((x0c = xml_child_each(x0, x0c, CX_ELMNT)) != NULL)
xml_purge(x0c);
if (xnacm){
if ((ret = nacm_datanode_write(NULL, x0, NACM_DELETE, username, xnacm, cbret)) < 0)
goto done;
if (ret == 0)
goto fail;
permit = 1;
}
while ((x0c = xml_child_i(x0, 0)) != 0)
if (xml_purge(x0c) < 0)
goto done;
break;
default:
break;
}
}
else /* base tree empty */
switch(op){
#if 0 /* According to RFC6020 7.5.8 you cant delete a non-existing object.
On the other hand, the top-level cannot be removed anyway.
Additionally, I think this is irritating so I disable it.
I.e., curl -u andy:bar -sS -X DELETE http://localhost/restconf/data
*/
case OP_DELETE:
if (netconf_data_missing(cbret, "Data does not exist; cannot delete resource") < 0)
goto done;
goto fail;
break;
#endif
default:
break;
}
}
/* Special case top-level replace */
if (op == OP_REPLACE || op == OP_DELETE){
x0c = NULL;
else if (op == OP_REPLACE || op == OP_DELETE){
if (xnacm && !permit){
if ((ret = nacm_datanode_write(NULL, x1, NACM_UPDATE, username, xnacm, cbret)) < 0)
goto done;
if (ret == 0)
goto fail;
permit = 1;
}
while ((x0c = xml_child_i(x0, 0)) != 0)
xml_purge(x0c);
if (xml_purge(x0c) < 0)
goto done;
}
/* Loop through children of the modification tree */
x1c = NULL;
@ -946,7 +1004,7 @@ text_modify_top(struct text_handle *th,
}
#endif
if ((ret = text_modify(th, x0c, (yang_node*)yc, x0, x1c, op,
username,xnacm, cbret)) < 0)
username, xnacm, permit, cbret)) < 0)
goto done;
/* If xml return - ie netconf error xml tree, then stop and return OK */
if (ret == 0)

View file

@ -96,7 +96,7 @@ new "minmax: empty"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c xmlns="urn:example:clixon"/></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
# NYI
if false; then
if false; then # nyi
new "minmax: validate should fail"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error/></rpc-reply>]]>]]>$"

View file

@ -131,9 +131,6 @@ sudo su -c "$clixon_restconf -f $cfg -D $DBG -- -a" -s /bin/sh www-data &
sleep $RCWAIT
new "restconf DELETE whole datastore"
expecteq "$(curl -u andy:bar -sS -X DELETE http://localhost/restconf/data)" ""
new2 "auth get"
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/nacm-example:x)" 'null
'

View file

@ -1,239 +0,0 @@
#!/bin/bash
# Authentication and authorization and IETF NACM
# NACM data node rule
# @see RFC 8341 A.1 and A.4 (and permit-all from A.2)
# Tests for:
# deny-nacm: This rule denies the "guest" group any access to the
# /nacm subtree.
# permit-acme-config: This rule gives the "limited" group read-write
# access to the acme <config-parameters>.
# permit-dummy-interface: This rule gives the "limited" and "guest"
# groups read-update access to the acme <interface> entry named
# "dummy". This entry cannot be created or deleted by these groups;
# it can only be altered.
# permit-interface: This rule gives the "admin" group read-write
# access to all acme <interface> entries.
APPNAME=example
# include err() and new() functions and creates $dir
. ./lib.sh
. ./nacm.sh
cfg=$dir/conf_yang.xml
fyang=$dir/test.yang
cat <<EOF > $cfg
<config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_RESTCONF_DIR>/usr/local/lib/$APPNAME/restconf</CLICON_RESTCONF_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
<CLICON_CLI_GENMODEL_COMPLETION>1</CLICON_CLI_GENMODEL_COMPLETION>
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
<CLICON_XMLDB_PLUGIN>/usr/local/lib/xmldb/text.so</CLICON_XMLDB_PLUGIN>
<CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY>
<CLICON_NACM_MODE>internal</CLICON_NACM_MODE>
</config>
EOF
cat <<EOF > $fyang
module nacm-example{
yang-version 1.1;
namespace "urn:example:nacm";
prefix nacm;
import clixon-example {
prefix ex;
}
import ietf-netconf-acm {
prefix nacm;
}
leaf x{
type int32;
description "something to edit";
}
}
EOF
# The groups are slightly modified from RFC8341 A.1
# The rule-list is from A.2
RULES=$(cat <<EOF
<nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm">
<enable-nacm>false</enable-nacm>
<read-default>deny</read-default>
<write-default>deny</write-default>
<exec-default>deny</exec-default>
$NGROUPS
<rule-list>
<name>guest-acl</name>
<group>guest</group>
<rule>
<name>deny-nacm</name>
<path xmlns:n="urn:ietf:params:xml:ns:yang:ietf-netconf-acm">
/n:nacm
</path>
<access-operations>*</access-operations>
<action>deny</action>
<comment>
Deny the 'guest' group any access to the /nacm data.
</comment>
</rule>
</rule-list>
<rule-list>
<name>limited-acl</name>
<group>limited</group>
<rule>
<name>permit-acme-config</name>
<path xmlns:acme="http://example.com/ns/netconf">
/acme:acme-netconf/acme:config-parameters
</path>
<access-operations>
read create update delete
</access-operations>
<action>permit</action>
<comment>
Allow the 'limited' group complete access to the acme
NETCONF configuration parameters. Showing long form
of 'access-operations' instead of shorthand.
</comment>
</rule>
</rule-list>
<rule-list>
<name>guest-limited-acl</name>
<group>guest</group>
<group>limited</group>
<rule>
<name>permit-dummy-interface</name>
<path xmlns:acme="http://example.com/ns/itf">
/acme:interfaces/acme:interface[acme:name='dummy']
</path>
<access-operations>read update</access-operations>
<action>permit</action>
<comment>
Allow the 'limited' and 'guest' groups read
and update access to the dummy interface.
</comment>
</rule>
</rule-list>
<rule-list>
<name>admin-acl</name>
<group>admin</group>
<rule>
<name>permit-interface</name>
<path xmlns:acme="http://example.com/ns/itf">
/acme:interfaces/acme:interface
</path>
<access-operations>*</access-operations>
<action>permit</action>
<comment>
Allow the 'admin' group full access to all acme interfaces.
</comment>
</rule>
</rule-list>
$NADMIN
</nacm>
<x xmlns="urn:example:clixon">0</x>
EOF
)
exit # XXX
new "test params: -f $cfg"
if [ $BE -ne 0 ]; then
new "kill old backend"
sudo clixon_backend -zf $cfg
if [ $? -ne 0 ]; then
err
fi
new "start backend -s init -f $cfg"
sudo $clixon_backend -s init -f $cfg -D $DBG
if [ $? -ne 0 ]; then
err
fi
fi
new "kill old restconf daemon"
sudo pkill -u www-data -f "/www-data/clixon_restconf"
sleep 1
new "start restconf daemon (-a is enable basic authentication)"
sudo su -c "$clixon_restconf -f $cfg -D $DBG -- -a" -s /bin/sh www-data &
sleep $RCWAIT
new "auth set authentication config"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><edit-config><target><candidate/></target><config>$RULES</config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "commit it"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "enable nacm"
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"enable-nacm": true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" ""
#--------------- nacm enabled
new2 "auth get (wrong passwd: access denied)"
expecteq "$(curl -u andy:foo -sS -X GET http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "The requested URL was unauthorized"}}} '
new2 "auth get (access)"
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/example:x)" '{"example:x": 0}
'
#----------------Enable NACM
new "enable nacm"
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"enable-nacm": true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" ""
new2 "admin get nacm"
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/example:x)" '{"example:x": 0}
'
new2 "limited get nacm"
expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data/example:x)" '{"example:x": 0}
'
new2 "guest get nacm"
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/example:x)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "The requested URL was unauthorized"}}} '
new "admin edit nacm"
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"x": 1}' http://localhost/restconf/data/example:x)" ""
new2 "limited edit nacm"
expecteq "$(curl -u wilma:bar -sS -X PUT -d '{"x": 2}' http://localhost/restconf/data/example:x)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}} '
new2 "guest edit nacm"
expecteq "$(curl -u guest:bar -sS -X PUT -d '{"x": 3}' http://localhost/restconf/data/example:x)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "The requested URL was unauthorized"}}} '
new "Kill restconf daemon"
sudo pkill -u www-data -f "/www-data/clixon_restconf"
if [ $BE -eq 0 ]; then
exit # BE
fi
new "Kill backend"
# Check if premature kill
pid=`pgrep -u root -f clixon_backend`
if [ -z "$pid" ]; then
err "backend already dead"
fi
# kill backend
sudo clixon_backend -z -f $cfg
if [ $? -ne 0 ]; then
err "kill backend"
fi
rm -rf $dir

View file

@ -151,9 +151,6 @@ sudo su -c "$clixon_restconf -f $cfg -D $DBG -- -a" -s /bin/sh www-data &
sleep $RCWAIT
new "restconf DELETE whole datastore"
expecteq "$(curl -u andy:bar -sS -X DELETE http://localhost/restconf/data)" ""
new2 "auth get"
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/clixon-example:state)" '{"clixon-example:state": {"op": "42"}}
'

View file

@ -6,17 +6,19 @@
# @see test_nacm.sh is slightly modified - this follows the RFC more closely
# See RFC 8341 A.1 and A.2
# Note: use clixon-example instead of ietf-netconf-monitoring since the latter is
# Tests for
# deny-ncm: This rule prevents the "guest" group from reading any
# monitoring information in the "clixon-example" YANG
# module.
# permit-ncm: This rule allows the "limited" group to read the
# "clixon-example" YANG module.
# permit-exec: This rule allows the "limited" group to invoke any
# protocol operation supported by the server.
# permit-all: This rule allows the "admin" group complete access to
# all content in the server. No subsequent rule will match for the
# "admin" group because of this module rule
# A) Three tracks in the code for leaf/leaf-list, container/lists, and root
# B) Three operations: create, update, delete (write)
# C) Two access operations: permit, deny (also default deny/permit)
# This gives 18 testcases
# Set group access:
# - Admin: permit: create, update, delete
# - Limit: permit: create, delete; deny: update
# - Guest: permit: update; deny: create delete
# ops\track:| root | leaf | list
#-----------+--------+--------+----------
# create | na | p/d | p/d
# update | p/d | p/d | p/d
# delete | p/d | p/d | p/d
APPNAME=example
# include err() and new() functions and creates $dir
@ -62,6 +64,17 @@ module nacm-example{
type int32;
description "something to edit";
}
list a{
key k;
leaf k{
type string;
}
container b{
leaf c{
type string;
}
}
}
}
EOF
@ -69,77 +82,51 @@ EOF
# The rule-list is from A.2
RULES=$(cat <<EOF
<nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm">
<enable-nacm>false</enable-nacm>
<enable-nacm>true</enable-nacm>
<read-default>deny</read-default>
<write-default>deny</write-default>
<exec-default>deny</exec-default>
<exec-default>permit</exec-default>
$NGROUPS
<rule-list>
<name>limited-acl</name>
<group>limited</group>
<rule>
<name>permit-create-delete</name>
<module-name>nacm-example</module-name>
<access-operations>read create delete</access-operations>
<action>permit</action>
</rule>
<rule>
<name>deny-update</name>
<module-name>nacm-example</module-name>
<access-operations>read update</access-operations>
<action>deny</action>
</rule>
</rule-list>
<rule-list>
<name>guest-acl</name>
<group>guest</group>
<rule>
<name>permit-get</name>
<module-name>ietf-netconf</module-name>
<rpc-name>*</rpc-name>
<access-operations>exec</access-operations>
<name>permit-update</name>
<module-name>nacm-example</module-name>
<access-operations>read update</access-operations>
<action>permit</action>
<comment>
Allow invocation of get rpc
</comment>
</rule>
<rule>
<name>permit-read</name>
<module-name>clixon-example</module-name>
<access-operations>read</access-operations>
<action>permit</action>
<comment>
Do not allow guests any access to the NETCONF
monitoring information.
</comment>
</rule>
<rule>
<name>deny-write</name>
<module-name>clixon-example</module-name>
<access-operations>*</access-operations>
<name>deny-create-delete</name>
<module-name>nacm-example</module-name>
<access-operations>read create delete</access-operations>
<action>deny</action>
<comment>
Do not allow guests any access to the NETCONF
monitoring information.
</comment>
</rule>
</rule-list>
<rule-list>
<name>limited-acl</name>
<group>limited</group>
<rule>
<name>permit-ncm</name>
<module-name>clixon-example</module-name>
<access-operations>read create update delete</access-operations>
<action>permit</action>
<comment>
Allow write access to the NETCONF monitoring information.
</comment>
</rule>
<rule>
<name>permit-exec</name>
<module-name>*</module-name>
<access-operations>exec</access-operations>
<action>permit</action>
<comment>
Allow invocation of the supported server operations.
</comment>
</rule>
</rule-list>
$NADMIN
</nacm>
<x xmlns="urn:example:nacm">42</x>
<translate xmlns="urn:example:clixon"><k>key42</k><value>val42</value></translate>
<translate xmlns="urn:example:clixon"><k>key43</k><value>val43</value></translate>
EOF
)
@ -167,40 +154,103 @@ sudo su -c "$clixon_restconf -f $cfg -D $DBG -- -a" -s /bin/sh www-data &
sleep $RCWAIT
new "auth set authentication config"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><edit-config><target><candidate/></target><config>$RULES</config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
# Set nacm from scratch
nacm(){
new "auth set authentication config"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><edit-config><target><candidate/></target><config operation='replace'>$RULES</config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "commit it"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "commit it"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "enable nacm"
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"enable-nacm": true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" ""
new "enable nacm"
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"enable-nacm": true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" ""
}
#--------------- nacm enabled
#----WRITE access
#user:admin
new2 "admin read element ok"
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/clixon-example:translate=key42/value)" '{"clixon-example:value": "val42"}
#--------------- enable nacm
nacm
# ops\track:| root | leaf | list
#-----------+--------+--------+----------
# create | n/a | xp/dx | p/d
# update | p/d | xp/dx | p/d
# delete | p/d | xp/dx | p/d
#----------root
new2 "update root list default deny"
expecteq "$(curl -u wilma:bar -sS -H 'Content-Type: application/yang-data+xml' -X PUT http://localhost/restconf/data -d '<data><x xmlns="urn:example:nacm">42</x>$RULES</data>')" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}} '
# replace all, then must include NACM rules as well
MSG="<data>$RULES</data>"
new "update root list permit"
expecteq "$(curl -u andy:bar -sS -H 'Content-Type: application/yang-data+xml' -X PUT http://localhost/restconf/data -d "$MSG")" ''
new "delete root list deny"
expecteq "$(curl -u wilma:bar -sS -X DELETE http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}} '
new "delete root permit"
expecteq "$(curl -u andy:bar -sS -X DELETE http://localhost/restconf/data)" ''
#--------------- re-enable nacm
nacm
#----------leaf
new2 "create leaf deny"
expecteq "$(curl -u guest:bar -sS -H 'Content-Type: application/yang-data+xml' -X PUT http://localhost/restconf/data/nacm-example:x -d '<x xmlns="urn:example:nacm">42</x>')" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "access denied"}}} '
new "create leaf permit"
expecteq "$(curl -u wilma:bar -sS -H 'Content-Type: application/yang-data+xml' -X PUT http://localhost/restconf/data/nacm-example:x -d '<x xmlns="urn:example:nacm">42</x>')" ''
new2 "update leaf deny"
expecteq "$(curl -u wilma:bar -sS -H 'Content-Type: application/yang-data+xml' -X PUT http://localhost/restconf/data/nacm-example:x -d '<x xmlns="urn:example:nacm">99</x>')" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "access denied"}}} '
new "update leaf permit"
expecteq "$(curl -u guest:bar -sS -H 'Content-Type: application/yang-data+xml' -X PUT http://localhost/restconf/data/nacm-example:x -d '<x xmlns="urn:example:nacm">99</x>')" ''
new2 "read leaf check"
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/nacm-example:x)" '{"nacm-example:x": 99}
'
new "admin write element ok"
expecteq "$(curl -u andy:bar -sS -X PUT http://localhost/restconf/data/clixon-example:translate=key42/value -d '{"clixon-example:value": "val99"}')"
new2 "delete leaf deny"
expecteq "$(curl -u guest:bar -sS -X DELETE http://localhost/restconf/data/nacm-example:x)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "access denied"}}} '
#user:limit
new2 "limit read element ok"
expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data/clixon-example:translate=key42/value)" '{"clixon-example:value": "val99"}
new "delete leaf permit"
expecteq "$(curl -u wilma:bar -sS -X DELETE http://localhost/restconf/data/nacm-example:x)" ''
#----- list/container
new2 "create list deny"
expecteq "$(curl -u guest:bar -sS -H 'Content-Type: application/yang-data+xml' -X PUT http://localhost/restconf/data/nacm-example:a=key42 -d '<a xmlns="urn:example:nacm"><k>key42</k><b><c>str</c></b></a>')" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "access denied"}}} '
new "create list permit"
expecteq "$(curl -u wilma:bar -sS -H 'Content-Type: application/yang-data+xml' -X PUT http://localhost/restconf/data/nacm-example:a=key42 -d '<a xmlns="urn:example:nacm"><k>key42</k><b><c>str</c></b></a>')" ''
new2 "update list deny"
expecteq "$(curl -u wilma:bar -sS -H 'Content-Type: application/yang-data+xml' -X PUT http://localhost/restconf/data/nacm-example:a=key42 -d '<a xmlns="urn:example:nacm"><k>key42</k><b><c>update</c></b></a>')" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "access denied"}}} '
new "update list permit"
expecteq "$(curl -u guest:bar -sS -H 'Content-Type: application/yang-data+xml' -X PUT http://localhost/restconf/data/nacm-example:a=key42 -d '<a xmlns="urn:example:nacm"><k>key42</k><b><c>update</c></b></a>')" ''
new2 "read list check"
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/nacm-example:a)" '{"nacm-example:a": [{"k": "key42","b": {"c": "update"}}]}
'
new "limit write element ok"
expecteq "$(curl -u wilma:bar -sS -X PUT http://localhost/restconf/data/clixon-example:translate=key42/value -d '{"clixon-example:value": "val55"}')"
new2 "delete list deny"
expecteq "$(curl -u guest:bar -sS -X DELETE http://localhost/restconf/data/nacm-example:a=key42)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "access denied"}}} '
#user:guest
new2 "guest read element ok"
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/clixon-example:translate=key42/value)" '{"clixon-example:value": "val55"}
'
new "delete list permit"
expecteq "$(curl -u wilma:bar -sS -X DELETE http://localhost/restconf/data/nacm-example:a=key42)" ''
new2 "guest write element ok"
expecteq "$(curl -u guest:bar -sS -X PUT http://localhost/restconf/data/clixon-example:translate=key42/value -d '{"clixon-example:value": "val99"}')" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "access denied"}}} '
#----- default deny (clixon-example limit and guest have default access)
new2 "default create list deny"
expecteq "$(curl -u wilma:bar -sS -X PUT http://localhost/restconf/data/clixon-example:translate=key42 -d '{"clixon-example:translate": [{"k": "key42","value": "val42"}]}')" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}} '
new2 "create list permit"
expecteq "$(curl -u andy:bar -sS -X PUT http://localhost/restconf/data/clixon-example:translate=key42 -d '{"clixon-example:translate": [{"k": "key42","value": "val42"}]}')" ''
new2 "default update list deny"
expecteq "$(curl -u wilma:bar -sS -X PUT http://localhost/restconf/data/clixon-example:translate=key42 -d '{"clixon-example:translate": [{"k": "key42","value": "val99"}]}')" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}} '
new2 "default delete list deny"
expecteq "$(curl -u wilma:bar -sS -X DELETE http://localhost/restconf/data/clixon-example:translate=key42)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}} '
new "Kill restconf daemon"
sudo pkill -u www-data -f "/www-data/clixon_restconf"

View file

@ -143,22 +143,22 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><can
# LEAF_LISTS
new "add two entries to leaf-list user order"
new "add two entries (c,b) to leaf-list user order"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y0 xmlns="urn:example:clixon">c</y0><y0 xmlns="urn:example:clixon">b</y0></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "add one entry to leaf-list user order"
new "add one entry (a) to leaf-list user order"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y0 xmlns="urn:example:clixon">a</y0></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf commit"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "add one entry to leaf-list user order after commit"
new "add one entry (0) to leaf-list user order after commit"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y0 xmlns="urn:example:clixon">0</y0></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf commit"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "verify leaf-list user order in running (as entered)"
new "verify leaf-list user order in running (as entered: c,b,a,0)"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><running/></source><filter type="xpath" select="/y0"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><y0 xmlns="urn:example:clixon">c</y0><y0 xmlns="urn:example:clixon">b</y0><y0 xmlns="urn:example:clixon">a</y0><y0 xmlns="urn:example:clixon">0</y0></data></rpc-reply>]]>]]>$'
# LISTS