diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f5079e3..ec014366 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -77,12 +77,10 @@ * CLICON_YANG_MAIN_FILE Provides a filename with a single module filename. * CLICON_YANG_MAIN_DIR Provides a directory where all yang modules should be loaded. * NACM extension (RFC8341) - * NACM Data node READ access module support (RFC8341 3.4.5) + * 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. * RFC 8341 Example A.2 implemented, see: [test/test_nacm_module.sh] - * Remaining work: - * data-node module write/create/delete/update - * 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. diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c index c9efa40a..936f03f1 100644 --- a/apps/backend/backend_client.c +++ b/apps/backend/backend_client.c @@ -214,7 +214,7 @@ from_client_get_config(clicon_handle h, goto ok; } /* Pre-NACM access step */ - if ((ret = nacm_access(h, username, &xnacm)) < 0) + if ((ret = nacm_access_h(h, username, &xnacm)) < 0) goto done; if (ret == 0){ /* Do NACM validation */ if (xpath_vec(xret, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) @@ -407,7 +407,7 @@ from_client_get(clicon_handle h, goto ok; } /* Pre-NACM access step */ - if ((ret = nacm_access(h, username, &xnacm)) < 0) + if ((ret = nacm_access_h(h, username, &xnacm)) < 0) goto done; if (ret == 0){ /* Do NACM validation */ if (xpath_vec(xret, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) @@ -1052,7 +1052,7 @@ from_client_msg(clicon_handle h, clicon_debug(1, "%s module:%s rpc:%s", __FUNCTION__, module, rpc); /* Pre-NACM access step */ xnacm = NULL; - if ((ret = nacm_access(h, username, &xnacm)) < 0) + if ((ret = nacm_access_h(h, username, &xnacm)) < 0) goto done; if (ret == 0){ /* Do NACM validation */ /* NACM rpc operation exec validation */ diff --git a/apps/cli/cli_generate.c b/apps/cli/cli_generate.c index 70c126bd..62ed1e49 100644 --- a/apps/cli/cli_generate.c +++ b/apps/cli/cli_generate.c @@ -212,6 +212,7 @@ yang2cli_var_sub(clicon_handle h, if (strcmp(type, "enumeration") == 0 || strcmp(type, "bits") == 0){ cprintf(cb, " choice:"); i = 0; + yi = NULL; while ((yi = yn_each((yang_node*)ytype, yi)) != NULL){ if (yi->ys_keyword != Y_ENUM && yi->ys_keyword != Y_BIT) continue; diff --git a/datastore/text/clixon_xmldb_text.c b/datastore/text/clixon_xmldb_text.c index 8c64616f..2e5ad5ea 100644 --- a/datastore/text/clixon_xmldb_text.c +++ b/datastore/text/clixon_xmldb_text.c @@ -615,6 +615,8 @@ text_modify(struct text_handle *th, cxobj *x0p, cxobj *x1, enum operation_type op, + char *username, + cxobj *xnacm, cbuf *cbret) { int retval = -1; @@ -626,6 +628,7 @@ text_modify(struct text_handle *th, cxobj *x0c; /* base child */ cxobj *x0b; /* base body */ cxobj *x1c; /* mod child */ + char *x0bstr; /* mod body string */ char *x1bstr; /* mod body string */ yang_stmt *yc; /* yang child */ cxobj **x0vec = NULL; @@ -679,12 +682,33 @@ 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; } - if (xml_value_set(x0b, x1bstr) < 0) - goto done; + else{ + 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) + goto done; + if (ret == 0) + goto fail; + } + if (xml_value_set(x0b, x1bstr) < 0) + goto done; + } + } + } break; case OP_DELETE: @@ -784,7 +808,8 @@ text_modify(struct text_handle *th, x1cname = xml_name(x1c); x0c = x0vec[i++]; yc = yang_find_datanode(y0, x1cname); - if ((ret = text_modify(th, x0c, (yang_node*)yc, x0, x1c, op, cbret)) < 0) + if ((ret = text_modify(th, x0c, (yang_node*)yc, x0, x1c, op, + username, xnacm, cbret)) < 0) goto done; /* If xml return - ie netconf error xml tree, then stop and return OK */ if (ret == 0) @@ -834,6 +859,8 @@ text_modify_top(struct text_handle *th, cxobj *x1, yang_spec *yspec, enum operation_type op, + char *username, + cxobj *xnacm, cbuf *cbret) { int retval = -1; @@ -860,6 +887,10 @@ text_modify_top(struct text_handle *th, 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); @@ -914,7 +945,8 @@ text_modify_top(struct text_handle *th, x0c = NULL; } #endif - if ((ret = text_modify(th, x0c, (yang_node*)yc, x0, x1c, op, cbret)) < 0) + if ((ret = text_modify(th, x0c, (yang_node*)yc, x0, x1c, op, + username,xnacm, cbret)) < 0) goto done; /* If xml return - ie netconf error xml tree, then stop and return OK */ if (ret == 0) @@ -997,6 +1029,7 @@ text_put(xmldb_handle xh, cxobj *x0 = NULL; struct db_element *de = NULL; int ret; + cxobj *xnacm = NULL; if (cbret == NULL){ clicon_err(OE_XML, EINVAL, "cbret is NULL"); @@ -1056,12 +1089,34 @@ text_put(xmldb_handle xh, #if 0 /* debug */ if (xml_apply0(x1, -1, xml_sort_verify, NULL) < 0) clicon_log(LOG_NOTICE, "%s: verify failed #1", __FUNCTION__); +#endif +#if 1 + { + char *mode; + cxobj *xnacm0 = NULL; + + mode = th->th_nacm_mode; + if (mode){ + if (strcmp(mode, "external")==0) + xnacm0 = th->th_nacm_xtree; + else if (strcmp(mode, "internal")==0) + xnacm0 = x0; + } + if (xnacm0 != NULL && + (xnacm = xpath_first(xnacm0, "nacm")) != NULL){ + /* Pre-NACM access step */ + if ((ret = nacm_access(mode, xnacm, username)) < 0) + goto done; + } + /* Here assume if xnacm is set (actually may be ret==0?) do NACM */ + } + #endif /* * Modify base tree x with modification x1. This is where the * new tree is made. */ - if ((ret = text_modify_top(th, x0, x1, yspec, op, cbret)) < 0) + if ((ret = text_modify_top(th, x0, x1, yspec, op, username, xnacm, cbret)) < 0) goto done; /* If xml return - ie netconf error xml tree, then stop and return OK */ if (ret == 0) diff --git a/lib/clixon/clixon_nacm.h b/lib/clixon/clixon_nacm.h index 670e7eec..f7a57318 100644 --- a/lib/clixon/clixon_nacm.h +++ b/lib/clixon/clixon_nacm.h @@ -45,11 +45,29 @@ */ #define NACM_RECOVERY_USER "_nacm_recovery" +/* + * Types + */ +/* NACM access rights, + * Note that these are not the same as netconf operations + * @see rfc8341 3.2.2 + * @see enum operation_type Netconf operations + */ +enum nacm_access{ + NACM_CREATE, + NACM_READ, + NACM_UPDATE, + NACM_DELETE, + NACM_EXEC +}; /* * Prototypes */ int nacm_rpc(char *rpc, char *module, char *username, cxobj *xnacm, cbuf *cbret); int nacm_datanode_read(cxobj *xt, cxobj **xvec, size_t xlen, char *username, cxobj *nacm_xtree); -int nacm_access(clicon_handle h, char *username, cxobj **xnacmp); +int nacm_datanode_write(cxobj *xt, cxobj *xr, enum nacm_access access, + char *username, cxobj *xnacm, cbuf *cbret); +int nacm_access_h(clicon_handle h, char *username, cxobj **xnacmp); +int nacm_access(char *mode, cxobj *xnacmin, char *username); #endif /* _CLIXON_NACM_H */ diff --git a/lib/src/clixon_nacm.c b/lib/src/clixon_nacm.c index a29fe485..f24a429c 100644 --- a/lib/src/clixon_nacm.c +++ b/lib/src/clixon_nacm.c @@ -72,13 +72,16 @@ * Incoming RPC Message Validation Step 7 (c) * The rule's "access-operations" leaf has the "exec" bit set or * has the special value "*". + * @param[in] mode Primary mode, eg read, create, update, delete, exec + * @param[in] mode2 Secondary mode, eg "write" * @retval 0 No match * @retval 1 Match * @note access_operations is bit-fields */ static int -nacm_match_access(char *access_operations, - char *mode) +match_access(char *access_operations, + char *mode, + char *mode2) { if (access_operations==NULL) return 0; @@ -86,6 +89,8 @@ nacm_match_access(char *access_operations, return 1; if (strstr(access_operations, mode)!=NULL) return 1; + if (mode2 && strstr(access_operations, mode2)!=NULL) + return 1; return 0; } @@ -146,7 +151,7 @@ nacm_rule_rpc(char *rpc, module_rule, rpc_rule, access_operations, action); if (module_rule && (strcmp(module_rule,"*")==0 || strcmp(module_rule,module)==0)){ - if (nacm_match_access(access_operations, "exec")){ + if (match_access(access_operations, "exec", NULL)){ if (rpc_rule==NULL || strcmp(rpc_rule, "*")==0 || strcmp(rpc_rule, rpc)==0){ /* Here is a matching rule */ @@ -171,13 +176,15 @@ nacm_rule_rpc(char *rpc, /*! Process nacm incoming RPC message validation steps * @param[in] module Yang module name * @param[in] rpc rpc name - * @param[in] username User name making access + * @param[in] username User name of requestor * @param[in] xnacm NACM xml tree * @param[out] cbret Cligen buffer result. Set to an error msg if retval=0. * @retval -1 Error * @retval 0 Not access and cbret set * @retval 1 Access * @see RFC8341 3.4.4. Incoming RPC Message Validation + * @see nacm_datanode_write + * @see nacm_datanode_read */ int nacm_rpc(char *rpc, @@ -190,7 +197,7 @@ nacm_rpc(char *rpc, cxobj *xrule; cxobj **gvec = NULL; /* groups */ size_t glen; - cxobj *xrlist; + cxobj *rlist; cxobj **rlistvec = NULL; /* rule-list */ size_t rlistlen; cxobj **rvec = NULL; /* rules */ @@ -198,6 +205,7 @@ nacm_rpc(char *rpc, int ret; int i, j; char *exec_default = NULL; + char *gname; /* 3. If the requested operation is the NETCONF protocol operation, then the protocol operation is permitted. @@ -224,12 +232,11 @@ nacm_rpc(char *rpc, if (xpath_vec(xnacm, "rule-list", &rlistvec, &rlistlen) < 0) goto done; for (i=0; i and Operations * Data nodes to which the client does not have read access are silently * omitted, along with any descendants, from the message. @@ -509,6 +520,9 @@ nacm_datanode_read_xr(cxobj *xt, * * A module rule has the "module-name" leaf set but no nodes from the * "rule-type" choice set. + * @see RFC8341 3.4.5. Data Node Access Validation + * @see nacm_datanode_write + * @see nacm_rpc */ int nacm_datanode_read(cxobj *xt, @@ -523,7 +537,6 @@ nacm_datanode_read(cxobj *xt, cxobj *xr; cxobj **rlistvec = NULL; /* rule-list */ size_t rlistlen; - cxobj **rvec = NULL; /* rules */ int i; char *read_default = NULL; cxobj *xrule; @@ -553,8 +566,8 @@ nacm_datanode_read(cxobj *xt, /* Loop through rule-list (steps 5,6,7) to find match of requested node */ xrule = NULL; - if (nacm_datanode_read_xr(xt, xr, gvec, glen, rlistvec, rlistlen, - &xrule) < 0) + if (nacm_data_read_xr(xt, xr, gvec, glen, rlistvec, rlistlen, + &xrule) < 0) goto done; if (xrule){ /* xrule match requested node xr */ if ((action = xml_find_body(xrule, "action")) == NULL) @@ -565,7 +578,7 @@ nacm_datanode_read(cxobj *xt, } else if (strcmp(action, "permit")==0) ;/* XXX recursively find denies in xr and purge them - * ie call nacm_datanode_read_xr recursively? + * ie call nacm_data_read_xr recursively? */ } else{ /* no rule matching xr, apply default */ @@ -596,6 +609,235 @@ nacm_datanode_read(cxobj *xt, retval = 0; done: clicon_debug(1, "%s retval:%d", __FUNCTION__, retval); + if (gvec) + free(gvec); + if (rlistvec) + free(rlistvec); + return retval; +} + +/*--------------------------------------------------------------- + * Datanode/module write (=create, delete, update) + */ + +/*! We have a rule matching user group. Now match proper write operation and module + * @retval -1 Error + * @retval 0 No Match + * @retval 1 Match + * @see RFC8341 3.4.5. Data Node Access Validation point (6) + * @see rule_data_read + */ +static int +rule_data_write(cxobj *xt, + cxobj *xr, + cxobj *xrule, + enum nacm_access access) +{ + int retval = -1; + char *path; + char *access_operations; + char *module_rule; /* rule module name */ + yang_stmt *ys; + yang_stmt *ymod; + char *module; + cxobj *xpath; /* xpath match */ + cxobj *xp; /* parent */ + + /* 6b) Either (1) the rule does not have a "rule-type" defined or + (2) the "rule-type" is "data-node" and the "path" matches the + requested data node, action node, or notification node. A + path is considered to match if the requested node is the node + specified by the path or is a descendant node of the path.*/ + if ((path = xml_find_body(xrule, "path")) == NULL){ + if (xml_find_body(xrule, "rpc-name") ||xml_find_body(xrule, "notification-name")) + goto nomatch; + } + /* 6c) For a "read" access operation, the rule's "access-operations" + leaf has the "read" bit set or has the special value "*" */ + + /* 6d) For a "create" access operation, the rule's + "access-operations" leaf has the "create" bit set or has the + special value "*". + 6e) For a "delete" access operation, the rule's + "access-operations" leaf has the "delete" bit set or has the + special value "*". + 6f) For an "update" access operation, the rule's + "access-operations" leaf has the "update" bit set or has the + special value "*". */ + access_operations = xml_find_body(xrule, "access-operations"); + switch (access){ + case NACM_CREATE: + if (!match_access(access_operations, "create", "write")) + goto nomatch; + break; + case NACM_UPDATE: + if (!match_access(access_operations, "update", "write")) + goto nomatch; + break; + case NACM_DELETE: + if (!match_access(access_operations, "delete", "write")) + goto nomatch; + break; + default: + break; + } + /* 6a) The rule's "module-name" leaf is "*" or equals the name of + * the YANG module where the requested data node is defined. */ + if ((module_rule = xml_find_body(xrule, "module-name")) == NULL) + goto nomatch; + if (strcmp(module_rule,"*")!=0){ + if ((ys = xml_spec(xr)) == NULL) + goto nomatch; + ymod = ys_module(ys); + module = ymod->ys_argument; + if (strcmp(module, module_rule) != 0) + goto nomatch; + } + /* Here module is matched, now check for path if any */ + if (path){ + if ((xpath = xpath_first(xt, "%s", path)) == NULL) + goto nomatch; + /* The requested node xr is the node specified by the path or is a + * descendant node of the path: + * xmatch is one of xvec[] or an ancestor of the xvec[] nodes. + */ + xp = xr; + do { + if (xpath == xp) + goto match; + } while ((xp = xml_parent(xp)) != NULL); + } + match: + retval = 1; + done: + return retval; + nomatch: + retval = 0; + goto done; +} + +/*! Make nacm datanode and module rule write access validation + * The operations of NACM are: create, read, update, delete, exec + * where write is short-hand for create+delete+update + * @param[in] xt XML root tree with "config" label. XXX? + * @param[in] xr XML requestor node (part of xt) + * @param[in] op NACM access of xr + * @param[in] username User making access + * @param[in] xnacm NACM xml tree + * @param[out] cbret Cligen buffer result. Set to an error msg if retval=0. + * @retval -1 Error + * @retval 0 Not access and cbret set + * @retval 1 Access + * @see RFC8341 3.4.5. Data Node Access Validation + * @see nacm_datanode_read + * @see nacm_rpc + */ +int +nacm_datanode_write(cxobj *xt, + cxobj *xr, + enum nacm_access access, + char *username, + cxobj *xnacm, + cbuf *cbret) +{ + int retval = -1; + cxobj **gvec = NULL; /* groups */ + size_t glen; + cxobj **rlistvec = NULL; /* rule-list */ + size_t rlistlen; + cxobj *rlist; + cxobj **rvec = NULL; /* rules */ + size_t rlen; + int i, j; + char *gname; + cxobj *xrule; + int match = 0; + char *action; + char *write_default; + + if (xnacm == NULL) + goto permit; + /* 3. Check all the "group" entries to see if any of them contain a + "user-name" entry that equals the username for the session + making the request. (If the "enable-external-groups" leaf is + "true", add to these groups the set of groups provided by the + transport layer.) */ + if (username == NULL) + goto step9; + /* User's group */ + if (xpath_vec(xnacm, "groups/group[user-name='%s']", &gvec, &glen, username) < 0) + goto done; + /* 4. If no groups are found, continue with step 9. */ + if (glen == 0) + goto step9; + /* 5. Process all rule-list entries, in the order they appear in the + configuration. If a rule-list's "group" leaf-list does not + match any of the user's groups, proceed to the next rule-list + entry. */ + if (xpath_vec(xnacm, "rule-list", &rlistvec, &rlistlen) < 0) + goto done; + for (i=0; iys_keyword != Y_BASE) continue; diff --git a/lib/src/clixon_yang_type.c b/lib/src/clixon_yang_type.c index ce43aec3..1ea116b7 100644 --- a/lib/src/clixon_yang_type.c +++ b/lib/src/clixon_yang_type.c @@ -475,6 +475,7 @@ cv_validate1(cg_var *cv, if (restype){ if (strcmp(restype, "enumeration") == 0){ found = 0; + yi = NULL; while ((yi = yn_each((yang_node*)yrestype, yi)) != NULL){ if (yi->ys_keyword != Y_ENUM) continue; @@ -500,6 +501,7 @@ cv_validate1(cg_var *cv, if ((v = vec[i]) == NULL || !strlen(v)) continue; found = 0; + yi = NULL; while ((yi = yn_each((yang_node*)yrestype, yi)) != NULL){ if (yi->ys_keyword != Y_BIT) continue; diff --git a/test/test_nacm_module.sh b/test/test_nacm_module.sh index d8427f5a..34356ba2 100755 --- a/test/test_nacm_module.sh +++ b/test/test_nacm_module.sh @@ -80,7 +80,7 @@ RULES=$(cat <guest-acl guest - deny-ncm + permit-read clixon-example * deny @@ -157,7 +157,7 @@ expecteq "$(curl -u andy:bar -sS -X PUT -d '{"enable-nacm": true}' http://localh #--------------- nacm enabled -#----READ monitoring information from example - (ietf-netconf-monitoring) +#----READ access #user:admin new2 "admin read ok" expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/clixon-example:translate)" '{"clixon-example:translate": [{"k": "key42","value": "val42"},{ "k": "key43","value": "val43"}]} diff --git a/test/test_nacm_module_write.sh b/test/test_nacm_module_write.sh new file mode 100755 index 00000000..5351ab33 --- /dev/null +++ b/test/test_nacm_module_write.sh @@ -0,0 +1,224 @@ +#!/bin/bash +# Authentication and authorization and IETF NACM +# NACM module rules +# A module rule has the "module-name" leaf set but no nodes from the +# "rule-type" choice set. +# @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 + +APPNAME=example +# include err() and new() functions and creates $dir +. ./lib.sh +. ./nacm.sh + +cfg=$dir/conf_yang.xml +fyang=$dir/nacm-example.yang + +cat < $cfg + + $cfg + /usr/local/share/clixon + $IETFRFC + $fyang + /usr/local/lib/$APPNAME/clispec + /usr/local/lib/$APPNAME/restconf + /usr/local/lib/$APPNAME/cli + $APPNAME + /usr/local/var/$APPNAME/$APPNAME.sock + /usr/local/lib/$APPNAME/backend + /usr/local/var/$APPNAME/$APPNAME.pidfile + 1 + /usr/local/var/$APPNAME + /usr/local/lib/xmldb/text.so + false + internal + +EOF + +cat < $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 ($USER added in admin group) +# The rule-list is from A.2 +RULES=$(cat < + false + deny + deny + deny + + $NGROUPS + + + guest-acl + guest + + permit-get + ietf-netconf + * + exec + permit + + Allow invocation of get rpc + + + + permit-read + clixon-example + read + permit + + Do not allow guests any access to the NETCONF + monitoring information. + + + + deny-write + clixon-example + * + deny + + Do not allow guests any access to the NETCONF + monitoring information. + + + + + + limited-acl + limited + + permit-ncm + clixon-example + read create update delete + permit + + Allow write access to the NETCONF monitoring information. + + + + permit-exec + * + exec + permit + + Allow invocation of the supported server operations. + + + + + $NADMIN + + + 42 + key42val42 + key43val43 +EOF +) + +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 "$RULES]]>]]>" "^]]>]]>$" + +new "commit it" +expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" "^]]>]]>$" + +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"} + ' + +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"}')" + +#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 "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"}')" + +#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"} + ' + +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"}}} ' + +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 diff --git a/test/test_nacm_protocol.sh b/test/test_nacm_protocol.sh index 41dfdefb..211ccad6 100755 --- a/test/test_nacm_protocol.sh +++ b/test/test_nacm_protocol.sh @@ -75,7 +75,7 @@ RULES=$(cat < false deny - deny + permit deny $NGROUPS