* RESTCONF strict namespace validation of data in POST and PUT.
* Accepted:
```
curl -X PUT http://localhost/restconf/data/mod:a -d {"mod:a":"x"}
```
* Not accepted (must prefix "a" with module):
```
curl -X PUT http://localhost/restconf/data/mod:a -d {"a":"x"}
```
* Undefine `RESTCONF_NS_DATA_CHECK` in include/clixon_custom.h to disable strict check.
This commit is contained in:
parent
40f3d48f2b
commit
de15b2bf80
9 changed files with 132 additions and 45 deletions
10
CHANGELOG.md
10
CHANGELOG.md
|
|
@ -69,6 +69,16 @@
|
||||||
|
|
||||||
### API changes on existing features (you may need to change your code)
|
### API changes on existing features (you may need to change your code)
|
||||||
|
|
||||||
|
* RESTCONF strict namespace validation of data in POST and PUT.
|
||||||
|
* Accepted:
|
||||||
|
```
|
||||||
|
curl -X PUT http://localhost/restconf/data/mod:a -d {"mod:a":"x"}
|
||||||
|
```
|
||||||
|
* Not accepted (must prefix "a" with module):
|
||||||
|
```
|
||||||
|
curl -X PUT http://localhost/restconf/data/mod:a -d {"a":"x"}
|
||||||
|
```
|
||||||
|
* Undefine `RESTCONF_NS_DATA_CHECK` in include/clixon_custom.h to disable strict check.
|
||||||
* Many validation functions have changed error parameter from cbuf to xml tree.
|
* Many validation functions have changed error parameter from cbuf to xml tree.
|
||||||
* XML trees are more flexible for utility tools
|
* XML trees are more flexible for utility tools
|
||||||
* If you use these(mostly internal), you need to change the error function: `generic_validate, from_validate_common, xml_yang_validate_all_top, xml_yang_validate_all, xml_yang_validate_add, xml_yang_validate_rpc, xml_yang_validate_list_key_only`
|
* If you use these(mostly internal), you need to change the error function: `generic_validate, from_validate_common, xml_yang_validate_all_top, xml_yang_validate_all, xml_yang_validate_add, xml_yang_validate_rpc, xml_yang_validate_list_key_only`
|
||||||
|
|
|
||||||
|
|
@ -437,13 +437,17 @@ api_data_post(clicon_handle h,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
enum operation_type op = OP_CREATE;
|
enum operation_type op = OP_CREATE;
|
||||||
|
cxobj *xdata0 = NULL; /* Original -d data struct (including top symbol) */
|
||||||
|
cxobj *xdata; /* -d data (without top symbol)*/
|
||||||
int i;
|
int i;
|
||||||
cxobj *xdata = NULL;
|
|
||||||
cbuf *cbx = NULL;
|
cbuf *cbx = NULL;
|
||||||
cxobj *xtop = NULL; /* xpath root */
|
cxobj *xtop = NULL; /* top of api-path */
|
||||||
cxobj *xbot = NULL;
|
cxobj *xbot = NULL; /* bottom of api-path */
|
||||||
cxobj *x;
|
yang_stmt *ybot = NULL; /* yang of xbot */
|
||||||
yang_stmt *y = NULL;
|
#ifdef RESTCONF_NS_DATA_CHECK
|
||||||
|
yang_stmt *ymodapi = NULL; /* yang module of api-path (if any) */
|
||||||
|
yang_stmt *ymoddata = NULL; /* yang module of data (-d) */
|
||||||
|
#endif
|
||||||
yang_stmt *yspec;
|
yang_stmt *yspec;
|
||||||
cxobj *xa;
|
cxobj *xa;
|
||||||
cxobj *xret = NULL;
|
cxobj *xret = NULL;
|
||||||
|
|
@ -469,8 +473,12 @@ api_data_post(clicon_handle h,
|
||||||
/* Translate api_path to xtop/xbot */
|
/* Translate api_path to xtop/xbot */
|
||||||
xbot = xtop;
|
xbot = xtop;
|
||||||
if (api_path){
|
if (api_path){
|
||||||
if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &y)) < 0)
|
if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &ybot)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
#ifdef RESTCONF_NS_DATA_CHECK
|
||||||
|
if (ybot)
|
||||||
|
ymodapi=ys_module(ybot);
|
||||||
|
#endif
|
||||||
if (ret == 0){ /* validation failed */
|
if (ret == 0){ /* validation failed */
|
||||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -486,7 +494,7 @@ api_data_post(clicon_handle h,
|
||||||
}
|
}
|
||||||
/* Parse input data as json or xml into xml */
|
/* Parse input data as json or xml into xml */
|
||||||
if (parse_xml){
|
if (parse_xml){
|
||||||
if (xml_parse_string(data, NULL, &xdata) < 0){
|
if (xml_parse_string(data, NULL, &xdata0) < 0){
|
||||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||||
|
|
@ -499,7 +507,7 @@ api_data_post(clicon_handle h,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ((ret = json_parse_str(data, yspec, &xdata, &xerr)) < 0){
|
if ((ret = json_parse_str(data, yspec, &xdata0, &xerr)) < 0){
|
||||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||||
|
|
@ -523,7 +531,7 @@ api_data_post(clicon_handle h,
|
||||||
/* 4.4.1: The message-body MUST contain exactly one instance of the
|
/* 4.4.1: The message-body MUST contain exactly one instance of the
|
||||||
* expected data resource.
|
* expected data resource.
|
||||||
*/
|
*/
|
||||||
if (xml_child_nr(xdata) != 1){
|
if (xml_child_nr(xdata0) != 1){
|
||||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||||
|
|
@ -534,15 +542,46 @@ api_data_post(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
x = xml_child_i(xdata,0);
|
xdata = xml_child_i(xdata0,0);
|
||||||
|
#ifdef RESTCONF_NS_DATA_CHECK
|
||||||
|
/* If the api-path (above) defines a module, then xdata must have a prefix
|
||||||
|
* and it match the module defined in api-path.
|
||||||
|
* In a POST, maybe there are cornercases where xdata (which is a child) and
|
||||||
|
* xbot (which is the parent) may have non-matching namespaces?
|
||||||
|
* This does not apply if api-path is / (no module)
|
||||||
|
*/
|
||||||
|
if (ys_module_by_xml(yspec, xdata, &ymoddata) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ymoddata && ymodapi){
|
||||||
|
if (ymoddata != ymodapi){
|
||||||
|
if (netconf_malformed_message_xml(&xerr, "Data is not prefixed with matching namespace") < 0)
|
||||||
|
goto done;
|
||||||
|
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||||
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (debug){
|
||||||
|
cbuf *ccc=cbuf_new();
|
||||||
|
if (clicon_xml2cbuf(ccc, xe, 0, 0) < 0)
|
||||||
|
goto done;
|
||||||
|
clicon_debug(1, "%s XE:%s", __FUNCTION__, cbuf_get(ccc));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||||
|
goto done;
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* RESTCONF_NS_DATA_CHECK */
|
||||||
|
|
||||||
/* Add operation (create/replace) as attribute */
|
/* Add operation (create/replace) as attribute */
|
||||||
if ((xa = xml_new("operation", x, NULL)) == NULL)
|
if ((xa = xml_new("operation", xdata, NULL)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
xml_type_set(xa, CX_ATTR);
|
xml_type_set(xa, CX_ATTR);
|
||||||
if (xml_value_set(xa, xml_operation2str(op)) < 0)
|
if (xml_value_set(xa, xml_operation2str(op)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Replace xbot with x, ie bottom of api-path with data */
|
/* Replace xbot with x, ie bottom of api-path with data */
|
||||||
if (xml_addsub(xbot, x) < 0)
|
if (xml_addsub(xbot, xdata) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Create text buffer for transfer to backend */
|
/* Create text buffer for transfer to backend */
|
||||||
if ((cbx = cbuf_new()) == NULL)
|
if ((cbx = cbuf_new()) == NULL)
|
||||||
|
|
@ -626,8 +665,8 @@ api_data_post(clicon_handle h,
|
||||||
xml_free(xretdis);
|
xml_free(xretdis);
|
||||||
if (xtop)
|
if (xtop)
|
||||||
xml_free(xtop);
|
xml_free(xtop);
|
||||||
if (xdata)
|
if (xdata0)
|
||||||
xml_free(xdata);
|
xml_free(xdata0);
|
||||||
if (cbx)
|
if (cbx)
|
||||||
cbuf_free(cbx);
|
cbuf_free(cbx);
|
||||||
return retval;
|
return retval;
|
||||||
|
|
@ -745,10 +784,14 @@ api_data_put(clicon_handle h,
|
||||||
cxobj *xdata0 = NULL; /* Original -d data struct (including top symbol) */
|
cxobj *xdata0 = NULL; /* Original -d data struct (including top symbol) */
|
||||||
cxobj *xdata; /* -d data (without top symbol)*/
|
cxobj *xdata; /* -d data (without top symbol)*/
|
||||||
cbuf *cbx = NULL;
|
cbuf *cbx = NULL;
|
||||||
cxobj *xtop = NULL; /* xpath root */
|
cxobj *xtop = NULL; /* top of api-path */
|
||||||
cxobj *xbot = NULL;
|
cxobj *xbot = NULL; /* bottom of api-path */
|
||||||
|
yang_stmt *ybot = NULL; /* yang of xbot */
|
||||||
|
#ifdef RESTCONF_NS_DATA_CHECK
|
||||||
|
yang_stmt *ymodapi = NULL; /* yang module of api-path (if any) */
|
||||||
|
yang_stmt *ymoddata = NULL; /* yang module of data (-d) */
|
||||||
|
#endif
|
||||||
cxobj *xparent;
|
cxobj *xparent;
|
||||||
yang_stmt *y = NULL;
|
|
||||||
yang_stmt *yp; /* yang parent */
|
yang_stmt *yp; /* yang parent */
|
||||||
yang_stmt *yspec;
|
yang_stmt *yspec;
|
||||||
cxobj *xa;
|
cxobj *xa;
|
||||||
|
|
@ -778,8 +821,12 @@ api_data_put(clicon_handle h,
|
||||||
/* Translate api_path to xtop/xbot */
|
/* Translate api_path to xtop/xbot */
|
||||||
xbot = xtop;
|
xbot = xtop;
|
||||||
if (api_path){
|
if (api_path){
|
||||||
if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &y)) < 0)
|
if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &ybot)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
#ifdef RESTCONF_NS_DATA_CHECK
|
||||||
|
if (ybot)
|
||||||
|
ymodapi=ys_module(ybot);
|
||||||
|
#endif
|
||||||
if (ret == 0){ /* validation failed */
|
if (ret == 0){ /* validation failed */
|
||||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -793,9 +840,10 @@ api_data_put(clicon_handle h,
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse input data as json or xml into xml */
|
/* Parse input data as json or xml into xml */
|
||||||
if (parse_xml){
|
if (parse_xml){
|
||||||
if (xml_parse_string(data, NULL, &xdata0) < 0){
|
if (xml_parse_string(data, yspec, &xdata0) < 0){
|
||||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||||
|
|
@ -844,20 +892,35 @@ api_data_put(clicon_handle h,
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
xdata = xml_child_i(xdata0,0);
|
xdata = xml_child_i(xdata0,0);
|
||||||
|
#ifdef RESTCONF_NS_DATA_CHECK
|
||||||
|
/* If the api-path (above) defines a module, then xdata must have a prefix
|
||||||
|
* and it match the module defined in api-path
|
||||||
|
* This does not apply if api-path is / (no module)
|
||||||
|
*/
|
||||||
|
if (ys_module_by_xml(yspec, xdata, &ymoddata) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ymoddata && ymodapi){
|
||||||
|
if (ymoddata != ymodapi){
|
||||||
|
if (netconf_malformed_message_xml(&xerr, "Data is not prefixed with matching namespace") < 0)
|
||||||
|
goto done;
|
||||||
|
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||||
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||||
|
goto done;
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* RESTCONF_NS_DATA_CHECK */
|
||||||
|
|
||||||
/* Add operation (create/replace) as attribute */
|
/* Add operation (create/replace) as attribute */
|
||||||
if ((xa = xml_new("operation", xdata, NULL)) == NULL)
|
if ((xa = xml_new("operation", xdata, NULL)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
xml_type_set(xa, CX_ATTR);
|
xml_type_set(xa, CX_ATTR);
|
||||||
if (xml_value_set(xa, xml_operation2str(op)) < 0)
|
if (xml_value_set(xa, xml_operation2str(op)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
#if 0
|
|
||||||
if (debug){
|
|
||||||
cbuf *ccc=cbuf_new();
|
|
||||||
if (clicon_xml2cbuf(ccc, xdata0, 0, 0) < 0)
|
|
||||||
goto done;
|
|
||||||
clicon_debug(1, "%s DATA:%s", __FUNCTION__, cbuf_get(ccc));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
/* Top-of tree, no api-path
|
/* Top-of tree, no api-path
|
||||||
* Replace xparent with x, ie bottom of api-path with data
|
* Replace xparent with x, ie bottom of api-path with data
|
||||||
*/
|
*/
|
||||||
|
|
@ -875,6 +938,7 @@ api_data_put(clicon_handle h,
|
||||||
* Not top-of-tree.
|
* Not top-of-tree.
|
||||||
*/
|
*/
|
||||||
clicon_debug(1, "%s x:%s xbot:%s",__FUNCTION__, dname, xml_name(xbot));
|
clicon_debug(1, "%s x:%s xbot:%s",__FUNCTION__, dname, xml_name(xbot));
|
||||||
|
|
||||||
/* Check same symbol in api-path as data */
|
/* Check same symbol in api-path as data */
|
||||||
if (strcmp(dname, xml_name(xbot))){
|
if (strcmp(dname, xml_name(xbot))){
|
||||||
if (netconf_operation_failed_xml(&xerr, "protocol", "Not same symbol in api-path as data") < 0)
|
if (netconf_operation_failed_xml(&xerr, "protocol", "Not same symbol in api-path as data") < 0)
|
||||||
|
|
@ -895,13 +959,13 @@ api_data_put(clicon_handle h,
|
||||||
* That is why the conditional is somewhat hairy
|
* That is why the conditional is somewhat hairy
|
||||||
*/
|
*/
|
||||||
xparent = xml_parent(xbot);
|
xparent = xml_parent(xbot);
|
||||||
if (y){
|
if (ybot){
|
||||||
/* Ensure list keys match between uri and data. That is:
|
/* Ensure list keys match between uri and data. That is:
|
||||||
* If data is on the form: -d {"a":{"k":1}} where a is list or leaf-list
|
* If data is on the form: -d {"a":{"k":1}} where a is list or leaf-list
|
||||||
* then uri-path must be ../a=1
|
* then uri-path must be ../a=1
|
||||||
* match_list_key() checks if this is true
|
* match_list_key() checks if this is true
|
||||||
*/
|
*/
|
||||||
if (match_list_keys(y, xdata, xbot) < 0){
|
if (match_list_keys(ybot, xdata, xbot) < 0){
|
||||||
if (netconf_operation_failed_xml(&xerr, "protocol", "api-path keys do not match data keys") < 0)
|
if (netconf_operation_failed_xml(&xerr, "protocol", "api-path keys do not match data keys") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||||
|
|
@ -916,7 +980,7 @@ api_data_put(clicon_handle h,
|
||||||
* If data is on the form: -d {"k":1} and its parent is a list "a"
|
* If data is on the form: -d {"k":1} and its parent is a list "a"
|
||||||
* then the uri-path must be "../a=1 (you cannot change a's key)"
|
* then the uri-path must be "../a=1 (you cannot change a's key)"
|
||||||
*/
|
*/
|
||||||
if ((yp = yang_parent_get(y)) != NULL &&
|
if ((yp = yang_parent_get(ybot)) != NULL &&
|
||||||
yang_keyword_get(yp) == Y_LIST){
|
yang_keyword_get(yp) == Y_LIST){
|
||||||
if ((ret = yang_key_match(yp, dname)) < 0)
|
if ((ret = yang_key_match(yp, dname)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -967,6 +1031,7 @@ api_data_put(clicon_handle h,
|
||||||
clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
|
clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
|
||||||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0)
|
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if ((xe = xpath_first(xret, "//rpc-error")) != NULL){
|
if ((xe = xpath_first(xret, "//rpc-error")) != NULL){
|
||||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -44,3 +44,7 @@
|
||||||
/* Use new xml_insert code on sorted xml lists
|
/* Use new xml_insert code on sorted xml lists
|
||||||
*/
|
*/
|
||||||
#define USE_XML_INSERT
|
#define USE_XML_INSERT
|
||||||
|
|
||||||
|
/* Make namespace check on RESTCONF PUT and POST -d data
|
||||||
|
*/
|
||||||
|
#define RESTCONF_NS_DATA_CHECK
|
||||||
|
|
|
||||||
|
|
@ -183,10 +183,10 @@ new "admin edit nacm"
|
||||||
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"nacm-example:x": 1}' http://localhost/restconf/data/nacm-example:x)" 0 ""
|
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"nacm-example:x": 1}' http://localhost/restconf/data/nacm-example:x)" 0 ""
|
||||||
|
|
||||||
new "limited edit nacm"
|
new "limited edit nacm"
|
||||||
expecteq "$(curl -u wilma:bar -sS -X PUT -d '{"x": 2}' http://localhost/restconf/data/nacm-example:x)" 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
expecteq "$(curl -u wilma:bar -sS -X PUT -d '{"nacm-example:x": 2}' http://localhost/restconf/data/nacm-example:x)" 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
||||||
|
|
||||||
new "guest edit nacm"
|
new "guest edit nacm"
|
||||||
expecteq "$(curl -u guest:bar -sS -X PUT -d '{"x": 3}' 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"}}}
'
|
expecteq "$(curl -u guest:bar -sS -X PUT -d '{"nacm-example:x": 3}' 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"}}}
'
|
||||||
|
|
||||||
new "cli show conf as admin"
|
new "cli show conf as admin"
|
||||||
expectfn "$clixon_cli -1 -U andy -l o -f $cfg show conf" 0 "^x 1;$"
|
expectfn "$clixon_cli -1 -U andy -l o -f $cfg show conf" 0 "^x 1;$"
|
||||||
|
|
|
||||||
|
|
@ -153,7 +153,7 @@ new "commit it"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "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)" 0 ""
|
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"ietf-netconf-acm:enable-nacm": true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 ""
|
||||||
|
|
||||||
#--------------- nacm enabled
|
#--------------- nacm enabled
|
||||||
|
|
||||||
|
|
@ -256,7 +256,7 @@ expecteof "$clixon_netconf -U guest -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml
|
||||||
#------------------ Set read-default permit
|
#------------------ Set read-default permit
|
||||||
|
|
||||||
new "admin set read-default permit"
|
new "admin set read-default permit"
|
||||||
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"read-default": "permit"}' http://localhost/restconf/data/ietf-netconf-acm:nacm/read-default)" 0 ""
|
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"ietf-netconf-acm:read-default": "permit"}' http://localhost/restconf/data/ietf-netconf-acm:nacm/read-default)" 0 ""
|
||||||
|
|
||||||
new "limit read ok"
|
new "limit read ok"
|
||||||
expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data/clixon-example:translate)" 0 '{"clixon-example:translate": [{"k": "key42","value": "val42"},{ "k": "key43","value": "val43"}]}
|
expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data/clixon-example:translate)" 0 '{"clixon-example:translate": [{"k": "key42","value": "val42"},{ "k": "key43","value": "val43"}]}
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,7 @@ nacm(){
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "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)" 0 ""
|
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"ietf-netconf-acm:enable-nacm": true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 ""
|
||||||
}
|
}
|
||||||
|
|
||||||
#--------------- enable nacm
|
#--------------- enable nacm
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ new "commit it"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "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)" 0 ""
|
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"ietf-netconf-acm:enable-nacm": true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 ""
|
||||||
|
|
||||||
#--------------- nacm enabled
|
#--------------- nacm enabled
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,9 @@ expectfn 'curl -s -X POST -d {"example:cont1":{"interface":{"type":"regular"}}}
|
||||||
new "restconf POST initial tree"
|
new "restconf POST initial tree"
|
||||||
expectfn 'curl -s -X POST -d {"example:cont1":{"interface":{"name":"local0","type":"regular"}}} http://localhost/restconf/data' 0 ""
|
expectfn 'curl -s -X POST -d {"example:cont1":{"interface":{"name":"local0","type":"regular"}}} http://localhost/restconf/data' 0 ""
|
||||||
|
|
||||||
|
new "restconf POST top without namespace"
|
||||||
|
expectfn 'curl -s -X POST -d {"cont1":{"interface":{"name":"local0","type":"regular"}}} http://localhost/restconf/data' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "unknown-element","error-info": {"bad-element": "cont1"},"error-severity": "error","error-message": "Unassigned yang spec"}}}'
|
||||||
|
|
||||||
new "restconf GET datastore initial"
|
new "restconf GET datastore initial"
|
||||||
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1" 0 '{"example:cont1": {"interface": \[{"name": "local0","type": "regular"}\]}}'
|
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1" 0 '{"example:cont1": {"interface": \[{"name": "local0","type": "regular"}\]}}'
|
||||||
|
|
||||||
|
|
@ -113,17 +116,19 @@ new "restconf GET if-type"
|
||||||
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1/interface=local0/type" 0 '{"example:type": "regular"}'
|
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1/interface=local0/type" 0 '{"example:type": "regular"}'
|
||||||
|
|
||||||
new "restconf POST interface without mandatory type"
|
new "restconf POST interface without mandatory type"
|
||||||
expectfn 'curl -s -X POST http://localhost/restconf/data/example:cont1 -d {"interface":{"name":"TEST"}} http://localhost/restconf/data/example:cont1' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "type"},"error-severity": "error","error-message": "Mandatory variable"}}}
'
|
expectfn 'curl -s -X POST http://localhost/restconf/data/example:cont1 -d {"example:interface":{"name":"TEST"}}' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "type"},"error-severity": "error","error-message": "Mandatory variable"}}}
'
|
||||||
|
|
||||||
new "restconf POST interface without mandatory key"
|
new "restconf POST interface without mandatory key"
|
||||||
expectfn 'curl -s -X POST http://localhost/restconf/data/example:cont1 -d {"interface":{"type":"regular"}}' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "name"},"error-severity": "error","error-message": "Mandatory key"}}}
'
|
expectfn 'curl -s -X POST http://localhost/restconf/data/example:cont1 -d {"example:interface":{"type":"regular"}}' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "name"},"error-severity": "error","error-message": "Mandatory key"}}}
'
|
||||||
|
|
||||||
new "restconf POST interface"
|
new "restconf POST interface"
|
||||||
expectfn 'curl -s -X POST -d {"example:interface":{"name":"TEST","type":"eth0"}} http://localhost/restconf/data/example:cont1' 0 ""
|
expectfn 'curl -s -X POST -d {"example:interface":{"name":"TEST","type":"eth0"}} http://localhost/restconf/data/example:cont1' 0 ""
|
||||||
|
|
||||||
# XXX should it be example:interface?
|
new "restconf POST interface without namespace"
|
||||||
|
expectfn 'curl -s -X POST -d {"interface":{"name":"TEST2","type":"eth0"}} http://localhost/restconf/data/example:cont1' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "rpc","error-tag": "malformed-message","error-severity": "error","error-message": "Data is not prefixed with matching namespace"}}}'
|
||||||
|
|
||||||
new "restconf POST again"
|
new "restconf POST again"
|
||||||
expecteq "$(curl -s -X POST -d '{"interface":{"name":"TEST","type":"eth0"}}' http://localhost/restconf/data/example:cont1)" 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "data-exists","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}
'
|
expecteq "$(curl -s -X POST -d '{"example:interface":{"name":"TEST","type":"eth0"}}' http://localhost/restconf/data/example:cont1)" 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "data-exists","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}
'
|
||||||
|
|
||||||
new "restconf POST from top"
|
new "restconf POST from top"
|
||||||
expecteq "$(curl -s -X POST -d '{"example:cont1":{"interface":{"name":"TEST","type":"eth0"}}}' http://localhost/restconf/data)" 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "data-exists","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}
'
|
expecteq "$(curl -s -X POST -d '{"example:cont1":{"interface":{"name":"TEST","type":"eth0"}}}' http://localhost/restconf/data)" 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "data-exists","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}
'
|
||||||
|
|
@ -162,16 +167,16 @@ new "restconf PUT initial datastore again"
|
||||||
expectfn 'curl -s -X PUT -d {"data":{"example:cont1":{"interface":{"name":"local0","type":"regular"}}}} http://localhost/restconf/data' 0 ""
|
expectfn 'curl -s -X PUT -d {"data":{"example:cont1":{"interface":{"name":"local0","type":"regular"}}}} http://localhost/restconf/data' 0 ""
|
||||||
|
|
||||||
new "restconf PUT change interface"
|
new "restconf PUT change interface"
|
||||||
expectfn 'curl -s -X PUT -d {"interface":{"name":"local0","type":"atm0"}} http://localhost/restconf/data/example:cont1/interface=local0' 0 ""
|
expectfn 'curl -s -X PUT -d {"example:interface":{"name":"local0","type":"atm0"}} http://localhost/restconf/data/example:cont1/interface=local0' 0 ""
|
||||||
|
|
||||||
new "restconf GET datastore atm"
|
new "restconf GET datastore atm"
|
||||||
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1" 0 '{"example:cont1": {"interface": \[{"name": "local0","type": "atm0"}\]}}'
|
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1" 0 '{"example:cont1": {"interface": \[{"name": "local0","type": "atm0"}\]}}'
|
||||||
|
|
||||||
new "restconf PUT add interface"
|
new "restconf PUT add interface"
|
||||||
expectfn 'curl -s -X PUT -d {"interface":{"name":"TEST","type":"eth0"}} http://localhost/restconf/data/example:cont1/interface=TEST' 0 ""
|
expectfn 'curl -s -X PUT -d {"example:interface":{"name":"TEST","type":"eth0"}} http://localhost/restconf/data/example:cont1/interface=TEST' 0 ""
|
||||||
|
|
||||||
new "restconf PUT change key error"
|
new "restconf PUT change key error"
|
||||||
expectfn 'curl -is -X PUT -d {"interface":{"name":"ALPHA","type":"eth0"}} http://localhost/restconf/data/example:cont1/interface=TEST' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "api-path keys do not match data keys"}}}'
|
expectfn 'curl -is -X PUT -d {"example:interface":{"name":"ALPHA","type":"eth0"}} http://localhost/restconf/data/example:cont1/interface=TEST' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "api-path keys do not match data keys"}}}'
|
||||||
|
|
||||||
new "restconf PUT change type to eth0 (non-key sub-element to list)"
|
new "restconf PUT change type to eth0 (non-key sub-element to list)"
|
||||||
expectfn 'curl -s -X PUT -d {"example:type":"eth0"} http://localhost/restconf/data/example:cont1/interface=local0/type' 0 ""
|
expectfn 'curl -s -X PUT -d {"example:type":"eth0"} http://localhost/restconf/data/example:cont1/interface=local0/type' 0 ""
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,9 @@ expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y -d {"list:a
|
||||||
new "restconf PUT change whole list entry (same keys)"
|
new "restconf PUT change whole list entry (same keys)"
|
||||||
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y -d {"list:a":{"b":"x","c":"y","nonkey":"z"}}' 0 ''
|
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y -d {"list:a":{"b":"x","c":"y","nonkey":"z"}}' 0 ''
|
||||||
|
|
||||||
|
new "restconf PUT change whole list entry (no namespace)(expect fail)"
|
||||||
|
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y -d {"a":{"b":"x","c":"y","nonkey":"z"}}' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "rpc","error-tag": "malformed-message","error-severity": "error","error-message": "Data is not prefixed with matching namespace"}}}'
|
||||||
|
|
||||||
new "restconf PUT change list entry (wrong keys)(expect fail)"
|
new "restconf PUT change list entry (wrong keys)(expect fail)"
|
||||||
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y -d {"list:a":{"b":"y","c":"x"}}' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "api-path keys do not match data keys"}}}'
|
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y -d {"list:a":{"b":"y","c":"x"}}' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "api-path keys do not match data keys"}}}'
|
||||||
|
|
||||||
|
|
@ -127,10 +130,10 @@ new "restconf PUT list-list single first key"
|
||||||
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x/e=z/f -d {"f":"z"}' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "rpc","error-tag": "malformed-message","error-severity": "error","error-message": "List key a length mismatch"}}}'
|
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x/e=z/f -d {"f":"z"}' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "rpc","error-tag": "malformed-message","error-severity": "error","error-message": "List key a length mismatch"}}}'
|
||||||
|
|
||||||
new "restconf PUT list-list just key ok"
|
new "restconf PUT list-list just key ok"
|
||||||
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y/e=z/f -d {"f":"z"}' 0 ''
|
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y/e=z/f -d {"list:f":"z"}' 0 ''
|
||||||
|
|
||||||
new "restconf PUT list-list just key just key wrong value (should fail)"
|
new "restconf PUT list-list just key just key wrong value (should fail)"
|
||||||
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y/e=z/f -d {"f":"wrong"}' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "api-path keys do not match data keys"}}}'
|
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y/e=z/f -d {"list:f":"wrong"}' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "api-path keys do not match data keys"}}}'
|
||||||
|
|
||||||
new "restconf PUT add list+leaf-list entry"
|
new "restconf PUT add list+leaf-list entry"
|
||||||
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y/f=u -d {"list:f":"u"}' 0 ''
|
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y/f=u -d {"list:f":"u"}' 0 ''
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue