From 71efe18f94f6c4e79d3ded1ab0630f42bc26efec Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Thu, 12 Mar 2020 14:58:30 +0100 Subject: [PATCH] NACM datanode write rules have been changed from looking at datastore being chekend (eg running/candidate/startup) to *only* look at running. Fixed: NACM datanode write problem: read/write/exec default rules did not work. --- CHANGELOG.md | 2 + apps/backend/backend_client.c | 68 ++++++++++--------- apps/backend/backend_commit.c | 1 + lib/clixon/clixon_data.h | 3 + lib/clixon/clixon_nacm.h | 13 +--- lib/src/clixon_data.c | 38 +++++++++++ lib/src/clixon_datastore_write.c | 25 ++----- lib/src/clixon_nacm.c | 51 ++++++-------- test/test_datastore.sh | 2 - test/test_nacm_default.sh | 113 +++++++++++++++++++++---------- test/test_nacm_module_write.sh | 47 +++++++------ 11 files changed, 205 insertions(+), 158 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e47c9b7..5fd393f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ Expected: Early March 2020 [search](https://clixon-docs.readthedocs.io/en/latest/xml.html#searching-in-xml) ### API changes on existing features (you may need to change your code) +* NACM datanode write rules have been changed from looking at datastore being chekend (eg running/candidate/startup) to *only* look at running. * C-API: * All uses of `api_path2xpath_cvv()` should be replaced by `api_path2xpath()` * `api_path2xpath()` added an `xerr` argument. @@ -97,6 +98,7 @@ Expected: Early March 2020 ### Corrected Bugs +* Fixed: NACM datanode write problem: read/write/exec default rules did not work. * Fixed [Makefile syntax error *** mixed implicit and normal rules #104](https://github.com/clicon/clixon/issues/104). Make operator `|=` seems not to work on GNU make version < 4. * Yang specs with recursive grouping/use statement is now fixed: instead of stack overflow, you get an error message and an exit * Fixed: Some state data was sorted but should not have been. diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c index 53103363..28caf4e0 100644 --- a/apps/backend/backend_client.c +++ b/apps/backend/backend_client.c @@ -444,21 +444,20 @@ client_statedata(clicon_handle h, * @see from_client_get */ static int -client_config_only(clicon_handle h, - cvec *nsc, - yang_stmt *yspec, - char *db, - char *xpath, - char *username, - int32_t depth, - cbuf *cbret) +client_get_config_only(clicon_handle h, + cvec *nsc, + yang_stmt *yspec, + char *db, + char *xpath, + char *username, + int32_t depth, + cbuf *cbret) { int retval = -1; cxobj *xret = NULL; cxobj *xnacm = NULL; cxobj **xvec = NULL; size_t xlen; - int ret; /* Note xret can be pruned by nacm below (and change name), * so zero-copy cant be used @@ -470,9 +469,8 @@ client_config_only(clicon_handle h, goto ok; } /* Pre-NACM access step */ - if ((ret = nacm_access_pre(h, username, NACM_DATA, &xnacm)) < 0) - goto done; - if (ret == 0){ /* Do NACM validation */ + xnacm = clicon_nacm_cache(h); + if (xnacm != NULL){ /* Do NACM validation */ if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) goto done; /* NACM datanode/module read validation */ @@ -494,8 +492,6 @@ client_config_only(clicon_handle h, done: if (xvec) free(xvec); - if (xnacm) - xml_free(xnacm); if (xret) xml_free(xret); return retval; @@ -582,7 +578,7 @@ from_client_get_config(clicon_handle h, goto ok; } } - if ((ret = client_config_only(h, nsc, yspec, db, xpath, username, -1, cbret)) < 0) + if ((ret = client_get_config_only(h, nsc, yspec, db, xpath, username, -1, cbret)) < 0) goto done; ok: retval = 0; @@ -1016,7 +1012,6 @@ from_client_get(clicon_handle h, cxobj *xfilter; char *xpath = NULL; cxobj *xret = NULL; - int ret; cxobj **xvec = NULL; size_t xlen; cxobj *xnacm = NULL; @@ -1030,6 +1025,7 @@ from_client_get(clicon_handle h, cxobj *xerr = NULL; cxobj *xr; cxobj *xb; + int ret; username = clicon_username_get(h); if ((yspec = clicon_dbspec_yang(h)) == NULL){ @@ -1072,7 +1068,7 @@ from_client_get(clicon_handle h, } } if (content == CONTENT_CONFIG){ /* config only, no state */ - if (client_config_only(h, nsc, yspec, "running", xpath, username, depth, cbret) < 0) + if (client_get_config_only(h, nsc, yspec, "running", xpath, username, depth, cbret) < 0) goto done; goto ok; } @@ -1173,9 +1169,8 @@ from_client_get(clicon_handle h, goto done; /* Pre-NACM access step */ - if ((ret = nacm_access_pre(h, username, NACM_DATA, &xnacm)) < 0) - goto done; - if (ret == 0){ /* Do NACM validation */ + xnacm = clicon_nacm_cache(h); + if (xnacm != NULL){ /* Do NACM validation */ if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) goto done; /* NACM datanode/module read validation */ @@ -1201,8 +1196,6 @@ from_client_get(clicon_handle h, xml_free(xerr); if (xpath) free(xpath); - if (xnacm) - xml_free(xnacm); if (xvec) free(xvec); if (nsc) @@ -1565,6 +1558,7 @@ from_client_msg(clicon_handle h, cxobj *xnacm = NULL; cxobj *xret = NULL; uint32_t id; + enum nacm_credentials_t creds; clicon_debug(1, "%s", __FUNCTION__); yspec = clicon_dbspec_yang(h); @@ -1627,22 +1621,21 @@ 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_pre(h, username, NACM_RPC, &xnacm)) < 0) + + if ((ret = nacm_access_pre(h, username, &xnacm)) < 0) goto done; - if (ret == 0){ /* Do NACM validation */ - enum nacm_credentials_t mode; - mode = clicon_nacm_credentials(h); - if ((ret = verify_nacm_user(mode, ce->ce_username, username, cbret)) < 0) + /* Cache XML NACM tree here. Use with caution, only valid on from_client_msg stack */ + if (clicon_nacm_cache_set(h, xnacm) < 0) + goto done; + if (ret == 0){ /* Do NACM RPC validation */ + creds = clicon_nacm_credentials(h); + if ((ret = verify_nacm_user(creds, ce->ce_username, username, cbret)) < 0) goto done; if (ret == 0) /* credentials fail */ goto reply; /* NACM rpc operation exec validation */ if ((ret = nacm_rpc(rpc, module, username, xnacm, cbret)) < 0) goto done; - if (xnacm){ - xml_free(xnacm); - xnacm = NULL; - } if (ret == 0) /* Not permitted and cbret set */ goto reply; } @@ -1658,7 +1651,13 @@ from_client_msg(clicon_handle h, goto done; goto reply; } - } + if (xnacm){ + xml_free(xnacm); + xnacm = NULL; + if (clicon_nacm_cache_set(h, NULL) < 0) + goto done; + } + } /* while */ reply: if (cbuf_len(cbret) == 0) if (netconf_operation_failed(cbret, "application", clicon_errno?clicon_err_reason:"unknown")< 0) @@ -1687,8 +1686,11 @@ from_client_msg(clicon_handle h, retval = 0; done: clicon_debug(1, "%s retval:%d", __FUNCTION__, retval); - if (xnacm) + if (xnacm){ xml_free(xnacm); + if (clicon_nacm_cache_set(h, NULL) < 0) + goto done; + } if (xret) xml_free(xret); if (xt) diff --git a/apps/backend/backend_commit.c b/apps/backend/backend_commit.c index 948a37e2..22b7d410 100644 --- a/apps/backend/backend_commit.c +++ b/apps/backend/backend_commit.c @@ -362,6 +362,7 @@ startup_commit(clicon_handle h, goto done; /* 9, write (potentially modified) tree to running * XXX note here startup is copied to candidate, which may confuse everything + * XXX default values are overwritten */ if ((ret = xmldb_put(h, "running", OP_REPLACE, td->td_target, clicon_username_get(h), cbret)) < 0) diff --git a/lib/clixon/clixon_data.h b/lib/clixon/clixon_data.h index 43d7b934..0146c7e2 100644 --- a/lib/clixon/clixon_data.h +++ b/lib/clixon/clixon_data.h @@ -67,6 +67,9 @@ int clicon_nsctx_global_set(clicon_handle h, cvec *nsctx); cxobj * clicon_nacm_ext(clicon_handle h); int clicon_nacm_ext_set(clicon_handle h, cxobj *xn); +cxobj *clicon_nacm_cache(clicon_handle h); +int clicon_nacm_cache_set(clicon_handle h, cxobj *xn); + cxobj *clicon_conf_xml(clicon_handle h); int clicon_conf_xml_set(clicon_handle h, cxobj *x); diff --git a/lib/clixon/clixon_nacm.h b/lib/clixon/clixon_nacm.h index b1b94831..c43ccd69 100644 --- a/lib/clixon/clixon_nacm.h +++ b/lib/clixon/clixon_nacm.h @@ -52,16 +52,6 @@ enum nacm_access{ NACM_EXEC }; -/*! In RFC8341, NACM defines three access points: rpc - * 3.4.4 Incoming RPC Message Validation - * 3.4.5 Data Node Access Validation - * 3.4.6 Outgoing Authorization - */ -enum nacm_point { - NACM_RPC, - NACM_DATA, - NACM_NOTIFICATION, -}; /* * Prototypes */ @@ -69,7 +59,6 @@ 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_datanode_write(cxobj *xt, cxobj *xr, enum nacm_access access, char *username, cxobj *xnacm, cbuf *cbret); -int nacm_access_pre(clicon_handle h, char *username, enum nacm_point point, cxobj **xnacmp); -int nacm_access(clicon_handle h, char *mode, cxobj *xnacmin, char *username); +int nacm_access_pre(clicon_handle h, char *username, cxobj **xnacmp); #endif /* _CLIXON_NACM_H */ diff --git a/lib/src/clixon_data.c b/lib/src/clixon_data.c index 87d70627..061b2e0b 100644 --- a/lib/src/clixon_data.c +++ b/lib/src/clixon_data.c @@ -264,6 +264,44 @@ clicon_nacm_ext_set(clicon_handle h, return 0; } +/*! Get NACM (rfc 8341) XML parse tree cache + * @param[in] h Clicon handle + * @retval xn XML NACM tree, or NULL. Direct pointer, no copying + * @note Use with caution, only valid on a stack, direct pointer freed on function return + * @see from_client_msg + */ +cxobj * +clicon_nacm_cache(clicon_handle h) +{ + clicon_hash_t *cdat = clicon_data(h); + size_t len; + void *p; + + if ((p = clicon_hash_value(cdat, "nacm_cache", &len)) != NULL) + return *(cxobj **)p; + return NULL; +} + +/*! Set NACM (rfc 8341) external XML parse tree cache + * @param[in] h Clicon handle + * @param[in] xn XML Nacm tree direct pointer, no copying + * @note Use with caution, only valid on a stack, direct pointer freed on function return + * @see from_client_msg + */ +int +clicon_nacm_cache_set(clicon_handle h, + cxobj *xn) +{ + clicon_hash_t *cdat = clicon_data(h); + + /* It is the pointer to xn that should be copied by hash, + so we send a ptr to the ptr to indicate what to copy. + */ + if (clicon_hash_add(cdat, "nacm_cache", &xn, sizeof(xn)) == NULL) + return -1; + return 0; +} + /*! Get YANG specification for Clixon system options and features * Must use hash functions directly since they are not strings. * Example: features are typically accessed directly in the config tree. diff --git a/lib/src/clixon_datastore_write.c b/lib/src/clixon_datastore_write.c index f02b5f57..1423e108 100644 --- a/lib/src/clixon_datastore_write.c +++ b/lib/src/clixon_datastore_write.c @@ -830,9 +830,7 @@ xmldb_put(clicon_handle h, cxobj *x0 = NULL; db_elmnt *de = NULL; int ret; - cxobj *xnacm = NULL; - char *mode; - cxobj *xnacm0 = NULL; + cxobj *xnacm = NULL; cxobj *xmodst = NULL; cxobj *x; int permit = 0; /* nacm permit all */ @@ -874,23 +872,10 @@ xmldb_put(clicon_handle h, if (xml_apply0(x1, -1, xml_sort_verify, NULL) < 0) clicon_log(LOG_NOTICE, "%s: verify failed #1", __FUNCTION__); #endif - mode = clicon_option_str(h, "CLICON_NACM_MODE"); - if (mode){ - if (strcmp(mode, "external")==0) - xnacm0 = clicon_nacm_ext(h); - else if (strcmp(mode, "internal")==0) - xnacm0 = x0; - } - /* Create namespace context for with nacm namespace as default */ - if ((nsc = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:yang:ietf-netconf-acm")) == NULL) - goto done; - if (xnacm0 != NULL && - (xnacm = xpath_first(xnacm0, nsc, "nacm")) != NULL){ - /* Pre-NACM access step, if permit, then dont do any nacm checks in - * text_modify_* below */ - if ((permit = nacm_access(h, mode, xnacm, username)) < 0) - goto done; - } + + xnacm = clicon_nacm_cache(h); + permit = (xnacm==NULL); + /* Here assume if xnacm is set and !permit do NACM */ /* * Modify base tree x with modification x1. This is where the diff --git a/lib/src/clixon_nacm.c b/lib/src/clixon_nacm.c index b64799be..d0476207 100644 --- a/lib/src/clixon_nacm.c +++ b/lib/src/clixon_nacm.c @@ -832,14 +832,12 @@ nacm_datanode_write(cxobj *xt, * @endcode * @see RFC8341 3.4 Access Control Enforcement Procedures */ -int +static int nacm_access(clicon_handle h, - char *mode, cxobj *xnacm, char *username) { int retval = -1; - cxobj *xnacm0 = NULL; char *enabled; cxobj *x; cvec *nsc = NULL; @@ -847,17 +845,6 @@ nacm_access(clicon_handle h, clicon_debug(1, "%s", __FUNCTION__); if ((nsc = xml_nsctx_init(NULL, NACM_NS)) == NULL) goto done; - if (mode == NULL || strcmp(mode, "disabled") == 0) - goto permit; - /* 0. If nacm-mode is external, get NACM defintion from separet tree, - otherwise get it from internal configuration */ - if (strcmp(mode, "external") && strcmp(mode, "internal")){ - clicon_err(OE_XML, 0, "Invalid NACM mode: %s", mode); - goto done; - } - /* If config does not exist, then the operation is permitted. (?) */ - if (xnacm == NULL) - goto permit; /* Do initial nacm processing common to all access validation in * RFC8341 3.4 */ /* 1. If the "enable-nacm" leaf is set to "false", then the protocol @@ -876,8 +863,6 @@ nacm_access(clicon_handle h, done: if (nsc) xml_nsctx_free(nsc); - if (retval != 0 && xnacm0) - xml_free(xnacm0); clicon_debug(1, "%s retval:%d (0:deny 1:permit)", __FUNCTION__, retval); return retval; permit: @@ -891,7 +876,6 @@ nacm_access(clicon_handle h, * etc. If retval = 1 access is OK and skip next NACM step. * @param[in] h Clicon handle * @param[in] username User name of requestor - * @param[in] point NACM access control point * @param[out] xncam NACM XML tree, set if retval=0. Free after use * @retval -1 Error * @retval 0 OK but not validated. Need to do NACM step using xnacm @@ -910,7 +894,6 @@ nacm_access(clicon_handle h, int nacm_access_pre(clicon_handle h, char *username, - enum nacm_point point, cxobj **xnacmp) { int retval = -1; @@ -920,19 +903,27 @@ nacm_access_pre(clicon_handle h, cxobj *xnacm = NULL; cvec *nsc = NULL; + mode = clicon_option_str(h, "CLICON_NACM_MODE"); + if (mode == NULL) + goto permit; + else if (strcmp(mode, "disabled")==0) + goto permit; + else if (strcmp(mode, "external")==0){ + if ((x = clicon_nacm_ext(h))) + if ((xnacm0 = xml_dup(x)) == NULL) + goto done; + } + else if (strcmp(mode, "internal")==0){ + if (xmldb_get0(h, "running", nsc, "nacm", 1, &xnacm0, NULL) < 0) + goto done; + } + else{ + clicon_err(OE_XML, 0, "Invalid NACM mode: %s", mode); + goto done; + } + if ((nsc = xml_nsctx_init(NULL, NACM_NS)) == NULL) goto done; - if ((mode = clicon_option_str(h, "CLICON_NACM_MODE")) != NULL){ - if (strcmp(mode, "external")==0){ - if ((x = clicon_nacm_ext(h))) - if ((xnacm0 = xml_dup(x)) == NULL) - goto done; - } - else if (strcmp(mode, "internal")==0){ - if (xmldb_get0(h, "running", nsc, "nacm", 1, &xnacm0, NULL) < 0) - goto done; - } - } /* If config does not exist then the operation is permitted(?) */ if (xnacm0 == NULL) goto permit; @@ -943,7 +934,7 @@ nacm_access_pre(clicon_handle h, goto done; xnacm0 = NULL; /* Initial NACM steps and common to all NACM access validation. */ - if ((retval = nacm_access(h, mode, xnacm, username)) < 0) + if ((retval = nacm_access(h, xnacm, username)) < 0) goto done; if (retval == 0){ /* if retval == 0 then return an xml nacm tree */ *xnacmp = xnacm; diff --git a/test/test_datastore.sh b/test/test_datastore.sh index e0fc758e..d104fe69 100755 --- a/test/test_datastore.sh +++ b/test/test_datastore.sh @@ -49,10 +49,8 @@ EOF xml='12first-entry13second-entry23third-entryabcastring' - name=text - mydir=$dir/$name if [ ! -d $mydir ]; then diff --git a/test/test_nacm_default.sh b/test/test_nacm_default.sh index 73de7426..11da4fe7 100755 --- a/test/test_nacm_default.sh +++ b/test/test_nacm_default.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # Basic NACM default rule without any groups -# Start from startup db +# Start from startup db as well as init db and load using POST # Magic line must be first in script (see README.md) s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi @@ -63,6 +63,8 @@ EOF # 5: expected return value of test1 # 6: expected return value of test2 # 7: expected return value of test3 +# 8: startup mode: startup or init +# 9: Dont set default values (nullify them) testrun(){ enablenacm=$1 readdefault=$2 @@ -71,31 +73,52 @@ testrun(){ ret1=$5 ret2=$6 ret3=$7 + db=$8 + nulldef=$9 - # NACM in startup - sudo tee $dir/startup_db > /dev/null << EOF - - - ${enablenacm} - ${readdefault} - ${writedefault} - ${execdefault} - true - - 42 - + # Set default values (or not) + if [ $nulldef -ne 0 ]; then + # Defaults should be: true permit deny permit: + # nacm enabled, exec default permit, read permit (expect fail)" + # which means results should be 0 1 3 + # Also enable-nacm is present since otherwise the nacm container would be removed + # since it is non-presence + NACM=$(cat < + ${enablenacm} + EOF +) + else + NACM=$(cat < + ${enablenacm} + ${readdefault} + ${writedefault} + ${execdefault} + true + +EOF +) + fi + # Initial data + XML='42' + + # Use startup or set values with POST (below) + if [ $db = startup ]; then + sudo echo "$NACM$XML" > $dir/startup_db + fi + if [ $BE -ne 0 ]; then # Bring your own backend new "kill old backend" sudo clixon_backend -zf $cfg if [ $? -ne 0 ]; then err fi - new "start backend -s startup -f $cfg" - start_backend -s startup -f $cfg + new "start backend -s $db -f $cfg" + start_backend -s $db -f $cfg else - new "Restart backend as eg follows: -Ff $cfg -s startup" - sleep $BETIMEOUT + new "Restart backend as eg follows: -Ff $cfg -s $db" fi new "waiting" @@ -109,6 +132,15 @@ EOF new "waiting" wait_restconf + + # Use POST (instead of startup) + if [ $db = init ]; then + new "Set Initial data using POST" + expectpart "$(curl -u guest:bar -siS -X POST -H "Content-Type: application/yang-data+xml" -d "$XML" http://localhost/restconf/data)" 0 "HTTP/1.1 201 Created" + + new "Set NACM using POST" + expectpart "$(curl -u guest:bar -siS -X POST -H "Content-Type: application/yang-data+xml" -d "$NACM" http://localhost/restconf/data)" 0 "HTTP/1.1 201 Created" + fi #----------- First get case "$ret1" in @@ -165,35 +197,42 @@ EOF } # testrun # Run a lot of tests with different settings of default read/write/exec -new "nacm enabled and all defaults permit" -testrun true permit permit permit 0 0 0 +# Outer loop either starts from startup or inits config via restconf POST +for db in startup init; do + new "nacm enabled and all defaults permit" + testrun true permit permit permit 0 0 0 $db 0 -new "nacm disabled and all defaults permit" -testrun false permit permit permit 0 0 0 + new "nacm disabled and all defaults permit" + testrun false permit permit permit 0 0 0 $db 0 -new "nacm disabled and all defaults deny" -testrun false deny deny deny 0 0 0 + new "nacm disabled and all defaults deny" + testrun false deny deny deny 0 0 0 $db 0 -new "nacm enabled, all defaults deny (expect fail)" -testrun true deny deny deny 1 1 1 + new "nacm enabled, all defaults deny (expect fail)" + testrun true deny deny deny 1 1 1 $db 0 -new "nacm enabled, exec default deny - read permit (expect fail)" -testrun true permit deny deny 1 1 1 + new "nacm enabled, exec default deny - read permit (expect fail)" + testrun true permit deny deny 1 1 1 $db 0 -new "nacm enabled, exec default deny - write permit (expect fail)" -testrun true deny permit deny 1 1 1 + new "nacm enabled, exec default deny - write permit (expect fail)" + testrun true deny permit deny 1 1 1 $db 0 -new "nacm enabled, exec default deny read/write permit (expect fail)" -testrun true permit permit deny 1 1 1 + new "nacm enabled, exec default deny read/write permit (expect fail)" + testrun true permit permit deny 1 1 1 $db 0 -new "nacm enabled, exec default permit, all others deny (expect fail)" -testrun true deny deny permit 2 1 2 + new "nacm enabled, exec default permit, all others deny (expect fail)" + testrun true deny deny permit 2 1 2 $db 0 -new "nacm enabled, exec default permit, read permit (expect fail)" -testrun true permit deny permit 0 1 3 + new "nacm enabled, exec default permit, read permit (expect fail)" + testrun true permit deny permit 0 1 3 $db 0 # This is yang default -new "nacm enabled, exec default permit, write permit (expect fail)" -testrun true deny permit permit 2 0 2 + new "nacm enabled, with default values (no settings - should be same as previous)" + # note last 1 means nullify all default values) + testrun true xxx xxx xxx 0 1 3 init 1 + + new "nacm enabled, exec default permit, write permit (expect fail)" + testrun true deny permit permit 2 0 2 $db 0 +done rm -rf $dir diff --git a/test/test_nacm_module_write.sh b/test/test_nacm_module_write.sh index b67a1768..14dbf598 100755 --- a/test/test_nacm_module_write.sh +++ b/test/test_nacm_module_write.sh @@ -168,8 +168,7 @@ nacm(){ expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" "^]]>]]>$" new "enable nacm" - expectpart "$(curl -u andy:bar -sS -X PUT -H 'Content-Type: application/yang-data+json' -d '{"ietf-netconf-acm:enable-nacm":true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 "" -# -H 'Content-Type: application/yang-data+json' + expectpart "$(curl -u andy:bar -siS -X PUT -H 'Content-Type: application/yang-data+json' -d '{"ietf-netconf-acm:enable-nacm":true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 "HTTP/1.1 204 No Content" } #--------------- enable nacm @@ -184,75 +183,75 @@ nacm # replace all, then must include NACM rules as well MSG="$RULES" new "update root list permit" -expectpart "$(curl -u andy:bar -sS -H 'Content-Type: application/yang-data+xml' -X PUT http://localhost/restconf/data -d "$MSG")" 0 '' +expectpart "$(curl -u andy:bar -siS -H 'Content-Type: application/yang-data+xml' -X PUT http://localhost/restconf/data -d "$MSG")" 0 'HTTP/1.1 204 No Content' +# Usually a 'HTTP/1.1 100 Continue' as well new "delete root list deny" -expecteq "$(curl -u wilma:bar -sS -X DELETE http://localhost/restconf/data)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"default deny"}}} ' +expectpart "$(curl -u wilma:bar -siS -X DELETE http://localhost/restconf/data)" 0 'HTTP/1.1 403 Forbidden' '{"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)" 0 '' +expectpart "$(curl -u andy:bar -siS -X DELETE http://localhost/restconf/data)" 0 'HTTP/1.1 204 No Content' #--------------- re-enable nacm nacm #----------leaf new "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 '42')" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"access denied"}}} ' +expectpart "$(curl -u guest:bar -siS -H 'Content-Type: application/yang-data+xml' -X PUT http://localhost/restconf/data/nacm-example:x -d '42')" 0 'HTTP/1.1 403 Forbidden' '{"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 '42')" 0 '' +expectpart "$(curl -u wilma:bar -siS -H 'Content-Type: application/yang-data+xml' -X PUT http://localhost/restconf/data/nacm-example:x -d '42')" 0 'HTTP/1.1 201 Created' new "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 '99')" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"access denied"}}} ' +expectpart "$(curl -u wilma:bar -siS -H 'Content-Type: application/yang-data+xml' -X PUT http://localhost/restconf/data/nacm-example:x -d '99')" 0 'HTTP/1.1 403 Forbidden' '{"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 '99')" 0 '' +expectpart "$(curl -u guest:bar -siS -H 'Content-Type: application/yang-data+xml' -X PUT http://localhost/restconf/data/nacm-example:x -d '99')" 0 'HTTP/1.1 204 No Content' new "read leaf check" -expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/nacm-example:x)" 0 '{"nacm-example:x":99} - ' +expectpart "$(curl -u guest:bar -siS -X GET http://localhost/restconf/data/nacm-example:x)" 0 'HTTP/1.1 200 OK' '{"nacm-example:x":99}' new "delete leaf deny" -expecteq "$(curl -u guest:bar -sS -X DELETE http://localhost/restconf/data/nacm-example:x)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"access denied"}}} ' +expectpart "$(curl -u guest:bar -siS -X DELETE http://localhost/restconf/data/nacm-example:x)" 0 'HTTP/1.1 403 Forbidden' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"access denied"}}} ' new "delete leaf permit" -expecteq "$(curl -u wilma:bar -sS -X DELETE http://localhost/restconf/data/nacm-example:x)" 0 '' +expectpart "$(curl -u wilma:bar -siS -X DELETE http://localhost/restconf/data/nacm-example:x)" 0 'HTTP/1.1 204 No Content' #----- list/container new "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 'key42str')" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"access denied"}}} ' +expectpart "$(curl -u guest:bar -siS -H 'Content-Type: application/yang-data+xml' -X PUT http://localhost/restconf/data/nacm-example:a=key42 -d 'key42str')" 0 'HTTP/1.1 403 Forbidden' '{"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 'key42str')" 0 '' +expectpart "$(curl -u wilma:bar -siS -H 'Content-Type: application/yang-data+xml' -X PUT http://localhost/restconf/data/nacm-example:a=key42 -d 'key42str')" 0 'HTTP/1.1 201 Created' new "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 'key42update')" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"access denied"}}} ' +expectpart "$(curl -u wilma:bar -siS -H 'Content-Type: application/yang-data+xml' -X PUT http://localhost/restconf/data/nacm-example:a=key42 -d 'key42update')" 0 'HTTP/1.1 403 Forbidden' '{"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 'key42update')" 0 '' +expectpart "$(curl -u guest:bar -siS -H 'Content-Type: application/yang-data+xml' -X PUT http://localhost/restconf/data/nacm-example:a=key42 -d 'key42update')" 0 'HTTP/1.1 204 No Content' new "read list check" -expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/nacm-example:a=key42)" 0 '{"nacm-example:a":[{"k":"key42","b":{"c":"update"}}]} +expectpart "$(curl -u guest:bar -siS -X GET http://localhost/restconf/data/nacm-example:a=key42)" 0 'HTTP/1.1 200 OK' '{"nacm-example:a":[{"k":"key42","b":{"c":"update"}}]} ' new "delete list deny" -expecteq "$(curl -u guest:bar -sS -X DELETE http://localhost/restconf/data/nacm-example:a=key42)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"access denied"}}} ' +expectpart "$(curl -u guest:bar -siS -X DELETE http://localhost/restconf/data/nacm-example:a=key42)" 0 'HTTP/1.1 403 Forbidden' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"access denied"}}} ' new "delete list permit" -expecteq "$(curl -u wilma:bar -sS -X DELETE http://localhost/restconf/data/nacm-example:a=key42)" 0 '' +expectpart "$(curl -u wilma:bar -siS -X DELETE http://localhost/restconf/data/nacm-example:a=key42)" 0 'HTTP/1.1 204 No Content' #----- default deny (clixon-example limit and guest have default access) new "default create list deny" -expecteq "$(curl -u wilma:bar -sS -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/clixon-example:translate/translate=key42 -d '{"clixon-example:translate":[{"k":"key42","value":"val42"}]}')" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"default deny"}}} ' +expectpart "$(curl -u wilma:bar -siS -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/clixon-example:translate/translate=key42 -d '{"clixon-example:translate":[{"k":"key42","value":"val42"}]}')" 0 'HTTP/1.1 403 Forbidden' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"default deny"}}' new "create list permit" -expecteq "$(curl -u andy:bar -sS -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/clixon-example:translate/translate=key42 -d '{"clixon-example:translate": [{"k":"key42","value":"val42"}]}')" 0 '' +expectpart "$(curl -u andy:bar -siS -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/clixon-example:translate/translate=key42 -d '{"clixon-example:translate": [{"k":"key42","value":"val42"}]}')" 0 'HTTP/1.1 201 Created' new "default update list deny" -expecteq "$(curl -u wilma:bar -sS -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/clixon-example:translate=key42 -d '{"clixon-example:translate": [{"k":"key42","value":"val99"}]}')" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"default deny"}}} ' +expectpart "$(curl -u wilma:bar -siS -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/clixon-example:translate=key42 -d '{"clixon-example:translate": [{"k":"key42","value":"val99"}]}')" 0 'HTTP/1.1 403 Forbidden' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"default deny"}}' new "default delete list deny" -expecteq "$(curl -u wilma:bar -sS -X DELETE http://localhost/restconf/data/clixon-example:translate=key42)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"default deny"}}} ' +expectpart "$(curl -u wilma:bar -siS -X DELETE http://localhost/restconf/data/clixon-example:translate=key42)" 0 'HTTP/1.1 403 Forbidden' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"default deny"}}' if [ $RC -ne 0 ]; then new "Kill restconf daemon"