NACM cleanup, uniform rule function, change of function names, etc.
This commit is contained in:
parent
8bf5cb0de5
commit
1e4022e73c
13 changed files with 180 additions and 247 deletions
15
CHANGELOG.md
15
CHANGELOG.md
|
|
@ -76,13 +76,16 @@
|
||||||
* Note CLIXON_DATADIR (=/usr/local/share/clixon) need to be in the list
|
* Note CLIXON_DATADIR (=/usr/local/share/clixon) need to be in the list
|
||||||
* CLICON_YANG_MAIN_FILE Provides a filename with a single module filename.
|
* 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.
|
* CLICON_YANG_MAIN_DIR Provides a directory where all yang modules should be loaded.
|
||||||
* NACM extension (RFC8341)
|
* NACM (RFC8341) experimental
|
||||||
* NACM Data node READ and WRITE access module support (RFC8341 3.4.5)
|
* Incoming RPC Message validation is supported (3.4.4)
|
||||||
* Access control points added for `get`, `get-config`, `edit-config` in addition to incoming rpc.
|
* Data Node Access validation is supported (3.4.5), except:
|
||||||
* RFC 8341 Example A.2 implemented, see: [test/test_nacm_module.sh]
|
* rule-type data-node path is not supported
|
||||||
* Remaining work: data-node PATH
|
* Outgoing noitification aithorization is _not_ supported (3.4.6)
|
||||||
|
* RPC:s are supported _except_:
|
||||||
|
* `copy-config`for other src/target combinations than running/startup (3.2.6)
|
||||||
|
* `commit` - NACM is applied to candidate and running operations only (3.2.8)
|
||||||
|
* Client-side RPC:s are _not_ supported.
|
||||||
* Recovery user "_nacm_recovery" added.
|
* 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.
|
|
||||||
|
|
||||||
### API changes on existing features (you may need to change your code)
|
### API changes on existing features (you may need to change your code)
|
||||||
* Added `username` argument on `xmldb_put()` datastore function for NACM data-node write checks
|
* Added `username` argument on `xmldb_put()` datastore function for NACM data-node write checks
|
||||||
|
|
|
||||||
39
README.md
39
README.md
|
|
@ -220,35 +220,28 @@ so the clients can in principle fake a username.
|
||||||
|
|
||||||
NACM
|
NACM
|
||||||
====
|
====
|
||||||
Clixon includes an experimental Network Configuration Access Control Model (NACM) according to [RFC8341(NACM)](https://tools.ietf.org/html/rfc8341). It has limited functionality.
|
Clixon includes an experimental Network Configuration Access Control Model (NACM) according to [RFC8341(NACM)](https://tools.ietf.org/html/rfc8341).
|
||||||
|
|
||||||
The support is as follows:
|
To enable NACM:
|
||||||
|
|
||||||
* There is a yang config variable `CLICON_NACM_MODE` to set whether NACM is disabled, uses internal(embedded) NACM configuration, or external configuration. (See yang/clixon-config.yang)
|
* The `CLICON_NACM_MODE` config variable is by default `disabled`.
|
||||||
* If the mode is internal, NACM configurations is expected to be in the regular configuration, managed by regular candidate/runing/commit procedures. This mode may have some problems with bootstrapping.
|
* If the mode is internal`, NACM configurations are expected to be in the regular configuration, managed by regular candidate/runing/commit procedures. This mode may have some problems with bootstrapping.
|
||||||
* If the mode is `external`, the `CLICON_NACM_FILE` yang config variable contains the name of a separate configuration file containing the NACM configurations. After changes in this file, the backend needs to be restarted.
|
* If the mode is `external`, the `CLICON_NACM_FILE` yang config variable contains the name of a separate configuration file containing the NACM configurations. After changes in this file, the backend needs to be restarted.
|
||||||
* The [example](example/README.md) contains a http basic auth and a NACM backend callback for mandatory state variables.
|
|
||||||
* There are two [tests](test/README.md) using internal and external NACM config
|
|
||||||
* The backend provides a limited NACM support (when enabled) described below
|
|
||||||
|
|
||||||
NACM is implemented in the backend and a single access check is made
|
The [example](example/README.md) contains a http basic auth and a NACM backend callback for mandatory state variables.
|
||||||
in `from_client_msg()` when an internal netconf RPC has
|
|
||||||
just been received and decoded. The code is in `nacm_access()`.
|
|
||||||
|
|
||||||
The functionality is as follows:
|
NACM is implemented in the backend with incoming RPC and data node access control points.
|
||||||
* Notification is not supported
|
|
||||||
* Groups are supported
|
|
||||||
* Rule-lists are supported
|
|
||||||
* Rules are supported as follows
|
|
||||||
* module-name: fully supported
|
|
||||||
* access-operations: only '*' and 'exec' supported
|
|
||||||
* rpc-name: fully supported (eg edit-config/get-config, etc)
|
|
||||||
* action: fully supported (permit/deny)
|
|
||||||
|
|
||||||
The tests outlines an example of three groups (taken from the RFC): admin, limited and guest:
|
The functionality is as follows (references to sections in [RFC8341](https://tools.ietf.org/html/rfc8341)):
|
||||||
* admin: Full access
|
* Access control point support:
|
||||||
* limited: Read access (get and get-config)
|
* Incoming RPC Message validation is supported (3.4.4)
|
||||||
* guest: No access
|
* Data Node Access validation is supported (3.4.5), except:
|
||||||
|
* rule-type data-node path is not supported
|
||||||
|
* Outgoing noitification aithorization is _not_ supported (3.4.6)
|
||||||
|
* RPC:s are supported _except_:
|
||||||
|
* `copy-config`for other src/target combinations than running/startup (3.2.6)
|
||||||
|
* `commit` - NACM is applied to candidate and running operations only (3.2.8)
|
||||||
|
* Client-side RPC:s are _not_ supported.
|
||||||
|
|
||||||
Runtime
|
Runtime
|
||||||
=======
|
=======
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,7 @@ from_client_get_config(clicon_handle h,
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
/* Pre-NACM access step */
|
/* Pre-NACM access step */
|
||||||
if ((ret = nacm_access_h(h, username, &xnacm)) < 0)
|
if ((ret = nacm_access_pre(h, username, &xnacm)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0){ /* Do NACM validation */
|
if (ret == 0){ /* Do NACM validation */
|
||||||
if (xpath_vec(xret, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
if (xpath_vec(xret, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||||
|
|
@ -407,7 +407,7 @@ from_client_get(clicon_handle h,
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
/* Pre-NACM access step */
|
/* Pre-NACM access step */
|
||||||
if ((ret = nacm_access_h(h, username, &xnacm)) < 0)
|
if ((ret = nacm_access_pre(h, username, &xnacm)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0){ /* Do NACM validation */
|
if (ret == 0){ /* Do NACM validation */
|
||||||
if (xpath_vec(xret, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
if (xpath_vec(xret, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||||
|
|
@ -728,6 +728,10 @@ from_client_kill_session(clicon_handle h,
|
||||||
* @param[out] cbret Return xml value cligen buffer
|
* @param[out] cbret Return xml value cligen buffer
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval -1 Error. Send error message back to client.
|
* @retval -1 Error. Send error message back to client.
|
||||||
|
* NACM: If source running and target startup --> only exec permission
|
||||||
|
* else:
|
||||||
|
* - omit data nodes to which the client does not have read access
|
||||||
|
* - access denied if user lacks create/delete/update
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
from_client_copy_config(clicon_handle h,
|
from_client_copy_config(clicon_handle h,
|
||||||
|
|
@ -1052,7 +1056,7 @@ from_client_msg(clicon_handle h,
|
||||||
clicon_debug(1, "%s module:%s rpc:%s", __FUNCTION__, module, rpc);
|
clicon_debug(1, "%s module:%s rpc:%s", __FUNCTION__, module, rpc);
|
||||||
/* Pre-NACM access step */
|
/* Pre-NACM access step */
|
||||||
xnacm = NULL;
|
xnacm = NULL;
|
||||||
if ((ret = nacm_access_h(h, username, &xnacm)) < 0)
|
if ((ret = nacm_access_pre(h, username, &xnacm)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0){ /* Do NACM validation */
|
if (ret == 0){ /* Do NACM validation */
|
||||||
/* NACM rpc operation exec validation */
|
/* NACM rpc operation exec validation */
|
||||||
|
|
|
||||||
|
|
@ -323,6 +323,10 @@ candidate_commit(clicon_handle h,
|
||||||
* @param[out] cbret Return xml value cligen buffer
|
* @param[out] cbret Return xml value cligen buffer
|
||||||
* @retval 0 OK. This may indicate both ok and err msg back to client
|
* @retval 0 OK. This may indicate both ok and err msg back to client
|
||||||
* @retval -1 (Local) Error
|
* @retval -1 (Local) Error
|
||||||
|
* NACM: The server MUST determine the exact nodes in the running
|
||||||
|
* configuration datastore that are actually different and only check
|
||||||
|
* "create", "update", and "delete" access permissions for this set of
|
||||||
|
* nodes, which could be empty.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
from_client_commit(clicon_handle h,
|
from_client_commit(clicon_handle h,
|
||||||
|
|
@ -368,6 +372,7 @@ from_client_commit(clicon_handle h,
|
||||||
* @param[out] cbret Return xml value cligen buffer
|
* @param[out] cbret Return xml value cligen buffer
|
||||||
* @retval 0 OK. This may indicate both ok and err msg back to client
|
* @retval 0 OK. This may indicate both ok and err msg back to client
|
||||||
* @retval -1 (Local) Error
|
* @retval -1 (Local) Error
|
||||||
|
* NACM: No datastore permissions are needed.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
from_client_discard_changes(clicon_handle h,
|
from_client_discard_changes(clicon_handle h,
|
||||||
|
|
|
||||||
|
|
@ -306,6 +306,7 @@ You may also add a default method in the configuration file:
|
||||||
Yes. Systemd example files are provide for the backend and the
|
Yes. Systemd example files are provide for the backend and the
|
||||||
restconf daemon as part of the [example](../example/systemd).
|
restconf daemon as part of the [example](../example/systemd).
|
||||||
|
|
||||||
|
|
||||||
## How can I add extra XML?
|
## How can I add extra XML?
|
||||||
|
|
||||||
There are two ways to add extra XML to running database after start. Note that this XML is not "committed" into running.
|
There are two ways to add extra XML to running database after start. Note that this XML is not "committed" into running.
|
||||||
|
|
@ -474,6 +475,14 @@ To authenticate, the callback needs to return the value 1 and supply a username.
|
||||||
See [../apps/example/example_restconf.c] example_restconf_credentials() for
|
See [../apps/example/example_restconf.c] example_restconf_credentials() for
|
||||||
an example of HTTP basic auth.
|
an example of HTTP basic auth.
|
||||||
|
|
||||||
|
## What about access control?
|
||||||
|
|
||||||
|
Clixon has experimental support of the Network Configuration Access
|
||||||
|
Control Model defined in [RFC8341](https://tools.ietf.org/html/rfc8341)
|
||||||
|
|
||||||
|
Incoming RPC and data node access points are supported with some
|
||||||
|
limitations. See the (README)(../README.md) for more information.
|
||||||
|
|
||||||
## How do I write a CLI translator function?
|
## How do I write a CLI translator function?
|
||||||
|
|
||||||
The CLI can perform variable translation. This is useful if you want to
|
The CLI can perform variable translation. This is useful if you want to
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ 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_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,
|
int nacm_datanode_write(cxobj *xt, cxobj *xr, enum nacm_access access,
|
||||||
char *username, cxobj *xnacm, cbuf *cbret);
|
char *username, cxobj *xnacm, cbuf *cbret);
|
||||||
int nacm_access_h(clicon_handle h, char *username, cxobj **xnacmp);
|
int nacm_access_pre(clicon_handle h, char *username, cxobj **xnacmp);
|
||||||
int nacm_access(char *mode, cxobj *xnacmin, char *username);
|
int nacm_access(char *mode, cxobj *xnacmin, char *username);
|
||||||
|
|
||||||
#endif /* _CLIXON_NACM_H */
|
#endif /* _CLIXON_NACM_H */
|
||||||
|
|
|
||||||
|
|
@ -101,23 +101,9 @@ match_access(char *access_operations,
|
||||||
* @param[out] cbret Cligen buffer result. Set to an error msg if retval=0.
|
* @param[out] cbret Cligen buffer result. Set to an error msg if retval=0.
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* @retval 0 Matching rule AND Not access and cbret set
|
* @retval 0 Matching rule AND Not access and cbret set
|
||||||
* @retval 1 Matchung rule AND Access
|
* @retval 1 Matching rule AND Access
|
||||||
* @retval 2 No matching rule Goto step 10
|
* @retval 2 No matching rule Goto step 10
|
||||||
* From RFC8341 3.4.4. Incoming RPC Message Validation
|
* @see RFC8341 3.4.4. Incoming RPC Message Validation
|
||||||
+---------+-----------------+---------------------+-----------------+
|
|
||||||
| Method | Resource class | NETCONF operation | Access |
|
|
||||||
| | | | operation |
|
|
||||||
+---------+-----------------+---------------------+-----------------+
|
|
||||||
| OPTIONS | all | none | none |
|
|
||||||
| HEAD | all | <get>, <get-config> | read |
|
|
||||||
| GET | all | <get>, <get-config> | read |
|
|
||||||
| POST | datastore, data | <edit-config> | create |
|
|
||||||
| POST | operation | specified operation | execute |
|
|
||||||
| PUT | data | <edit-config> | create, update |
|
|
||||||
| PUT | datastore | <copy-config> | update |
|
|
||||||
| PATCH | data, datastore | <edit-config> | update |
|
|
||||||
| DELETE | data | <edit-config> | delete |
|
|
||||||
|
|
||||||
7.(cont) A rule matches if all of the following criteria are met:
|
7.(cont) A rule matches if all of the following criteria are met:
|
||||||
* The rule's "module-name" leaf is "*" or equals the name of
|
* The rule's "module-name" leaf is "*" or equals the name of
|
||||||
the YANG module where the protocol operation is defined.
|
the YANG module where the protocol operation is defined.
|
||||||
|
|
@ -133,44 +119,40 @@ match_access(char *access_operations,
|
||||||
static int
|
static int
|
||||||
nacm_rule_rpc(char *rpc,
|
nacm_rule_rpc(char *rpc,
|
||||||
char *module,
|
char *module,
|
||||||
cxobj *xrule,
|
cxobj *xrule)
|
||||||
cbuf *cbret)
|
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *module_rule; /* rule module name */
|
char *module_rule; /* rule module name */
|
||||||
char *rpc_rule;
|
char *rpc_rule;
|
||||||
char *access_operations;
|
char *access_operations;
|
||||||
char *action;
|
|
||||||
|
|
||||||
module_rule = xml_find_body(xrule, "module-name");
|
/* 7a) The rule's "module-name" leaf is "*" or equals the name of
|
||||||
rpc_rule = xml_find_body(xrule, "rpc-name");
|
the YANG module where the protocol operation is defined. */
|
||||||
/* XXX access_operations can be a set of bits */
|
if ((module_rule = xml_find_body(xrule, "module-name")) == NULL)
|
||||||
access_operations = xml_find_body(xrule, "access-operations");
|
goto nomatch;
|
||||||
action = xml_find_body(xrule, "action");
|
if (strcmp(module_rule,"*") && strcmp(module_rule,module))
|
||||||
clicon_debug(1, "%s: %s %s %s %s", __FUNCTION__,
|
goto nomatch;
|
||||||
module_rule, rpc_rule, access_operations, action);
|
/* 7b) Either (1) the rule does not have a "rule-type" defined or
|
||||||
if (module_rule &&
|
(2) the "rule-type" is "protocol-operation" and the
|
||||||
(strcmp(module_rule,"*")==0 || strcmp(module_rule,module)==0)){
|
"rpc-name" is "*" or equals the name of the requested
|
||||||
if (match_access(access_operations, "exec", NULL)){
|
protocol operation. */
|
||||||
if (rpc_rule==NULL ||
|
if ((rpc_rule = xml_find_body(xrule, "rpc-name")) == NULL){
|
||||||
strcmp(rpc_rule, "*")==0 || strcmp(rpc_rule, rpc)==0){
|
if (xml_find_body(xrule, "path") || xml_find_body(xrule, "notification-name"))
|
||||||
/* Here is a matching rule */
|
goto nomatch;
|
||||||
if (action && strcmp(action, "permit")==0){
|
|
||||||
retval = 1;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
if (netconf_access_denied(cbret, "protocol", "access denied") < 0)
|
|
||||||
goto done;
|
|
||||||
retval = 0;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
retval = 2; /* no matching rule */
|
if (rpc_rule && (strcmp(rpc_rule, "*") && strcmp(rpc_rule, rpc)))
|
||||||
|
goto nomatch;
|
||||||
|
/* 7c) The rule's "access-operations" leaf has the "exec" bit set or
|
||||||
|
has the special value "*". */
|
||||||
|
access_operations = xml_find_body(xrule, "access-operations");
|
||||||
|
if (!match_access(access_operations, "exec", NULL))
|
||||||
|
goto nomatch;
|
||||||
|
retval = 1;
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
|
nomatch:
|
||||||
|
retval = 0;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Process nacm incoming RPC message validation steps
|
/*! Process nacm incoming RPC message validation steps
|
||||||
|
|
@ -202,10 +184,11 @@ nacm_rpc(char *rpc,
|
||||||
size_t rlistlen;
|
size_t rlistlen;
|
||||||
cxobj **rvec = NULL; /* rules */
|
cxobj **rvec = NULL; /* rules */
|
||||||
size_t rlen;
|
size_t rlen;
|
||||||
int ret;
|
|
||||||
int i, j;
|
int i, j;
|
||||||
char *exec_default = NULL;
|
char *exec_default = NULL;
|
||||||
char *gname;
|
char *gname;
|
||||||
|
char *action;
|
||||||
|
int match= 0;
|
||||||
|
|
||||||
/* 3. If the requested operation is the NETCONF <close-session>
|
/* 3. If the requested operation is the NETCONF <close-session>
|
||||||
protocol operation, then the protocol operation is permitted.
|
protocol operation, then the protocol operation is permitted.
|
||||||
|
|
@ -249,25 +232,30 @@ nacm_rpc(char *rpc,
|
||||||
goto done;
|
goto done;
|
||||||
for (j=0; j<rlen; j++){
|
for (j=0; j<rlen; j++){
|
||||||
xrule = rvec[j];
|
xrule = rvec[j];
|
||||||
/* -1 error, 0 deny, 1 permit, 2 continue */
|
if ((match = nacm_rule_rpc(rpc, module, xrule)) < 0)
|
||||||
if ((ret = nacm_rule_rpc(rpc, module, xrule, cbret)) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
switch(ret){
|
if (match)
|
||||||
case 0: /* deny */
|
|
||||||
goto deny;
|
|
||||||
break;
|
break;
|
||||||
case 1: /* permit */
|
|
||||||
goto permit;
|
|
||||||
break;
|
|
||||||
case 2: /* no match, continue */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (match)
|
||||||
|
break;
|
||||||
if (rvec){
|
if (rvec){
|
||||||
free(rvec);
|
free(rvec);
|
||||||
rvec=NULL;
|
rvec=NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (match){
|
||||||
|
if ((action = xml_find_body(xrule, "action")) == NULL)
|
||||||
|
goto step10;
|
||||||
|
if (strcmp(action, "deny")==0){
|
||||||
|
if (netconf_access_denied(cbret, "application", "access denied") < 0)
|
||||||
|
goto done;
|
||||||
|
goto deny;
|
||||||
|
}
|
||||||
|
else if (strcmp(action, "permit")==0)
|
||||||
|
goto permit;
|
||||||
|
|
||||||
|
}
|
||||||
step10:
|
step10:
|
||||||
/* 10. If the requested protocol operation is defined in a YANG module
|
/* 10. If the requested protocol operation is defined in a YANG module
|
||||||
advertised in the server capabilities and the "rpc" statement
|
advertised in the server capabilities and the "rpc" statement
|
||||||
|
|
@ -277,7 +265,7 @@ nacm_rpc(char *rpc,
|
||||||
<kill-session> or <delete-config>, then the protocol operation
|
<kill-session> or <delete-config>, then the protocol operation
|
||||||
is denied. */
|
is denied. */
|
||||||
if (strcmp(rpc, "kill-session")==0 || strcmp(rpc, "delete-config")==0){
|
if (strcmp(rpc, "kill-session")==0 || strcmp(rpc, "delete-config")==0){
|
||||||
if (netconf_access_denied(cbret, "protocol", "default deny") < 0)
|
if (netconf_access_denied(cbret, "application", "default deny") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto deny;
|
goto deny;
|
||||||
}
|
}
|
||||||
|
|
@ -286,7 +274,7 @@ nacm_rpc(char *rpc,
|
||||||
exec_default = xml_find_body(xnacm, "exec-default");
|
exec_default = xml_find_body(xnacm, "exec-default");
|
||||||
if (exec_default ==NULL || strcmp(exec_default, "permit")==0)
|
if (exec_default ==NULL || strcmp(exec_default, "permit")==0)
|
||||||
goto permit;
|
goto permit;
|
||||||
if (netconf_access_denied(cbret, "protocol", "default deny") < 0)
|
if (netconf_access_denied(cbret, "application", "default deny") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto deny;
|
goto deny;
|
||||||
permit:
|
permit:
|
||||||
|
|
@ -307,45 +295,31 @@ nacm_rpc(char *rpc,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*---------------------------------------------------------------
|
/*---------------------------------------------------------------
|
||||||
* Datanode/module read
|
* Datanode/module read and write
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*! We have a rule matching user group. Now match proper read operation and module
|
/*! We have a rule matching user group. Now match proper write operation and module
|
||||||
* @see RFC8341 3.4.5. Data Node Access Validation point (6)
|
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* @retval 0 No Match
|
* @retval 0 No Match
|
||||||
* @retval 1 Match
|
* @retval 1 Match
|
||||||
* @see rule_data_write
|
* @see RFC8341 3.4.5. Data Node Access Validation point (6)
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
rule_data_read(cxobj *xrule,
|
nacm_rule_datanode(cxobj *xt,
|
||||||
cxobj *xr,
|
cxobj *xr,
|
||||||
cxobj *xt)
|
cxobj *xrule,
|
||||||
|
enum nacm_access access)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *xp; /* parent */
|
char *path;
|
||||||
char *access_operations;
|
char *access_operations;
|
||||||
char *module_rule; /* rule module name */
|
char *module_rule; /* rule module name */
|
||||||
yang_stmt *ys;
|
yang_stmt *ys;
|
||||||
yang_stmt *ymod;
|
yang_stmt *ymod;
|
||||||
char *module;
|
char *module;
|
||||||
char *path;
|
|
||||||
cxobj *xpath; /* xpath match */
|
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 "*" */
|
|
||||||
access_operations = xml_find_body(xrule, "access-operations");
|
|
||||||
if (!match_access(access_operations, "read", NULL))
|
|
||||||
goto nomatch;
|
|
||||||
/* 6a) The rule's "module-name" leaf is "*" or equals the name of
|
/* 6a) The rule's "module-name" leaf is "*" or equals the name of
|
||||||
* the YANG module where the requested data node is defined. */
|
* the YANG module where the requested data node is defined. */
|
||||||
if ((module_rule = xml_find_body(xrule, "module-name")) == NULL)
|
if ((module_rule = xml_find_body(xrule, "module-name")) == NULL)
|
||||||
|
|
@ -358,7 +332,46 @@ rule_data_read(cxobj *xrule,
|
||||||
if (strcmp(module, module_rule) != 0)
|
if (strcmp(module, module_rule) != 0)
|
||||||
goto nomatch;
|
goto nomatch;
|
||||||
}
|
}
|
||||||
/* Here module is matched, now check for path if any */
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
access_operations = xml_find_body(xrule, "access-operations");
|
||||||
|
switch (access){
|
||||||
|
case NACM_READ:
|
||||||
|
/* 6c) For a "read" access operation, the rule's "access-operations"
|
||||||
|
leaf has the "read" bit set or has the special value "*" */
|
||||||
|
if (!match_access(access_operations, "read", NULL))
|
||||||
|
goto nomatch;
|
||||||
|
break;
|
||||||
|
case NACM_CREATE:
|
||||||
|
/* 6d) For a "create" access operation, the rule's "access-operations"
|
||||||
|
leaf has the "create" bit set or has the special value "*". */
|
||||||
|
if (!match_access(access_operations, "create", "write"))
|
||||||
|
goto nomatch;
|
||||||
|
break;
|
||||||
|
case NACM_DELETE:
|
||||||
|
/* 6e) For a "delete" access operation, the rule's "access-operations"
|
||||||
|
leaf has the "delete" bit set or has the special value "*". */
|
||||||
|
if (!match_access(access_operations, "delete", "write"))
|
||||||
|
goto nomatch;
|
||||||
|
break;
|
||||||
|
case NACM_UPDATE:
|
||||||
|
/* 6f) For an "update" access operation, the rule's "access-operations"
|
||||||
|
leaf has the "update" bit set or has the special value "*". */
|
||||||
|
if (!match_access(access_operations, "update", "write"))
|
||||||
|
goto nomatch;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Here module is matched, now check for path if any NYI */
|
||||||
if (path){
|
if (path){
|
||||||
if ((xpath = xpath_first(xt, "%s", path)) == NULL)
|
if ((xpath = xpath_first(xt, "%s", path)) == NULL)
|
||||||
goto nomatch;
|
goto nomatch;
|
||||||
|
|
@ -420,13 +433,13 @@ nacm_data_read_xr(cxobj *xt,
|
||||||
continue;
|
continue;
|
||||||
/* 6. For each rule-list entry found, process all rules, in order,
|
/* 6. For each rule-list entry found, process all rules, in order,
|
||||||
until a rule that matches the requested access operation is
|
until a rule that matches the requested access operation is
|
||||||
found. (see 6 sub rules in rule_data_read)
|
found. (see 6 sub rules in nacm_rule_datanode
|
||||||
*/
|
*/
|
||||||
if (xpath_vec(rlist, "rule", &rvec, &rlen) < 0)
|
if (xpath_vec(rlist, "rule", &rvec, &rlen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
for (j=0; j<rlen; j++){ /* Loop through rules */
|
for (j=0; j<rlen; j++){ /* Loop through rules */
|
||||||
xrule = rvec[j];
|
xrule = rvec[j];
|
||||||
if ((match = rule_data_read(xrule, xr, xt)) < 0)
|
if ((match = nacm_rule_datanode(xt, xr, xrule, NACM_READ)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (match) /* xrule match */
|
if (match) /* xrule match */
|
||||||
break;
|
break;
|
||||||
|
|
@ -616,106 +629,6 @@ nacm_datanode_read(cxobj *xt,
|
||||||
return retval;
|
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
|
/*! Make nacm datanode and module rule write access validation
|
||||||
* The operations of NACM are: create, read, update, delete, exec
|
* The operations of NACM are: create, read, update, delete, exec
|
||||||
* where write is short-hand for create+delete+update
|
* where write is short-hand for create+delete+update
|
||||||
|
|
@ -790,17 +703,21 @@ nacm_datanode_write(cxobj *xt,
|
||||||
goto done;
|
goto done;
|
||||||
/* 6. For each rule-list entry found, process all rules, in order,
|
/* 6. For each rule-list entry found, process all rules, in order,
|
||||||
until a rule that matches the requested access operation is
|
until a rule that matches the requested access operation is
|
||||||
found. (see 6 sub rules in nacm_match_rule2)
|
found. (see 6 sub rules in nacm_rule_data_write)
|
||||||
*/
|
*/
|
||||||
for (j=0; j<rlen; j++){ /* Loop through rules */
|
for (j=0; j<rlen; j++){ /* Loop through rules */
|
||||||
xrule = rvec[j];
|
xrule = rvec[j];
|
||||||
if ((match = rule_data_write(xt, xr, xrule, access)) < 0)
|
if ((match = nacm_rule_datanode(xt, xr, xrule, access)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (match) /* match */
|
if (match) /* match */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (match)
|
if (match)
|
||||||
break;
|
break;
|
||||||
|
if (rvec){
|
||||||
|
free(rvec);
|
||||||
|
rvec = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (match){
|
if (match){
|
||||||
if ((action = xml_find_body(xrule, "action")) == NULL)
|
if ((action = xml_find_body(xrule, "action")) == NULL)
|
||||||
|
|
@ -934,7 +851,7 @@ nacm_access(char *mode,
|
||||||
* @retval 1 OK permitted. You do not need to do next NACM step
|
* @retval 1 OK permitted. You do not need to do next NACM step
|
||||||
* @code
|
* @code
|
||||||
* cxobj *xnacm = NULL;
|
* cxobj *xnacm = NULL;
|
||||||
* if ((ret = nacm_access_h(h, username, &xnacm)) < 0)
|
* if ((ret = nacm_access_pre(h, username, &xnacm)) < 0)
|
||||||
* err;
|
* err;
|
||||||
* if (ret == 0){
|
* if (ret == 0){
|
||||||
* // Next step NACM processing
|
* // Next step NACM processing
|
||||||
|
|
@ -943,11 +860,10 @@ nacm_access(char *mode,
|
||||||
* @endcode
|
* @endcode
|
||||||
* @see RFC8341 3.4 Access Control Enforcement Procedures
|
* @see RFC8341 3.4 Access Control Enforcement Procedures
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
nacm_access_h(clicon_handle h,
|
nacm_access_pre(clicon_handle h,
|
||||||
char *username,
|
char *username,
|
||||||
cxobj **xnacmp)
|
cxobj **xnacmp)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *mode;
|
char *mode;
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,9 @@ application. Assumes setup of http daemon as describe under apps/restonf
|
||||||
- site.sh Add your site-specific modifications here
|
- site.sh Add your site-specific modifications here
|
||||||
- test_nacm.sh Auth tests using internal NACM
|
- test_nacm.sh Auth tests using internal NACM
|
||||||
- test_nacm_ext.sh Auth tests using external NACM (separate file)
|
- test_nacm_ext.sh Auth tests using external NACM (separate file)
|
||||||
|
- test_nacm_protocol.sh Auth tests for incoming RPC:s
|
||||||
|
- test_nacm_module_read.sh Auth tests for data node read operations
|
||||||
|
- test_nacm_module_write.sh Auth tests for data node write operations
|
||||||
- test_cli.sh CLI tests
|
- test_cli.sh CLI tests
|
||||||
- test_netconf.sh Netconf tests
|
- test_netconf.sh Netconf tests
|
||||||
- test_restconf.sh Restconf tests
|
- test_restconf.sh Restconf tests
|
||||||
|
|
|
||||||
|
|
@ -165,16 +165,16 @@ expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data/nacm-exa
|
||||||
'
|
'
|
||||||
|
|
||||||
new2 "guest get nacm"
|
new2 "guest get nacm"
|
||||||
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/nacm-example:x)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "access denied"}}}
'
|
expecteq "$(curl -u guest:bar -sS -X GET 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"}}}
'
|
||||||
|
|
||||||
new "admin edit nacm"
|
new "admin edit nacm"
|
||||||
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"nacm-example:x": 1}' http://localhost/restconf/data/nacm-example:x)" ""
|
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"nacm-example:x": 1}' http://localhost/restconf/data/nacm-example:x)" ""
|
||||||
|
|
||||||
new2 "limited edit nacm"
|
new2 "limited edit nacm"
|
||||||
expecteq "$(curl -u wilma:bar -sS -X PUT -d '{"nacm-example:x": 2}' http://localhost/restconf/data/nacm-example:x)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","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)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
||||||
|
|
||||||
new2 "guest edit nacm"
|
new2 "guest edit nacm"
|
||||||
expecteq "$(curl -u guest:bar -sS -X PUT -d '{"nacm-example:x": 3}' http://localhost/restconf/data/nacm-example:x)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","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)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "access denied"}}}
'
|
||||||
|
|
||||||
new "Kill restconf daemon"
|
new "Kill restconf daemon"
|
||||||
sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
||||||
|
|
|
||||||
|
|
@ -177,16 +177,16 @@ expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data/nacm-exa
|
||||||
'
|
'
|
||||||
|
|
||||||
new2 "guest get nacm"
|
new2 "guest get nacm"
|
||||||
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/nacm-example:x)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "access denied"}}}
'
|
expecteq "$(curl -u guest:bar -sS -X GET 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"}}}
'
|
||||||
|
|
||||||
new "admin edit nacm"
|
new "admin edit nacm"
|
||||||
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"nacm-example:x": 1}' http://localhost/restconf/data/nacm-example:x)" ""
|
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"nacm-example:x": 1}' http://localhost/restconf/data/nacm-example:x)" ""
|
||||||
|
|
||||||
new2 "limited edit nacm"
|
new2 "limited edit nacm"
|
||||||
expecteq "$(curl -u wilma:bar -sS -X PUT -d '{"x": 2}' http://localhost/restconf/data/nacm-example:x)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
expecteq "$(curl -u wilma:bar -sS -X PUT -d '{"x": 2}' http://localhost/restconf/data/nacm-example:x)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
||||||
|
|
||||||
new2 "guest edit nacm"
|
new2 "guest edit nacm"
|
||||||
expecteq "$(curl -u guest:bar -sS -X PUT -d '{"x": 3}' http://localhost/restconf/data/nacm-example:x)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "access denied"}}}
'
|
expecteq "$(curl -u guest:bar -sS -X PUT -d '{"x": 3}' 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"}}}
'
|
||||||
|
|
||||||
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;$"
|
||||||
|
|
|
||||||
|
|
@ -214,22 +214,22 @@ expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data)" '{"dat
|
||||||
#user:guest
|
#user:guest
|
||||||
|
|
||||||
new2 "guest read fail"
|
new2 "guest read fail"
|
||||||
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/clixon-example:translate)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/clixon-example:translate)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
||||||
|
|
||||||
new2 "guest read netconf fail"
|
new2 "guest read netconf fail"
|
||||||
expecteof "$clixon_netconf -U guest -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/translate"/></get-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>protocol</error-type><error-tag>access-denied</error-tag><error-severity>error</error-severity><error-message>default deny</error-message></rpc-error></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -U guest -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/translate"/></get-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>access-denied</error-tag><error-severity>error</error-severity><error-message>default deny</error-message></rpc-error></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new2 "guest read element fail"
|
new2 "guest read element fail"
|
||||||
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/clixon-example:translate=key42/value)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/clixon-example:translate=key42/value)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
||||||
|
|
||||||
new2 "guest read other module fail"
|
new2 "guest read other module fail"
|
||||||
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/nacm-example:x)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/nacm-example:x)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
||||||
|
|
||||||
new2 "guest read state fail"
|
new2 "guest read state fail"
|
||||||
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/clixon-example:state)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/clixon-example:state)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
||||||
|
|
||||||
new2 "guest read top ok (part)"
|
new2 "guest read top ok (part)"
|
||||||
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
||||||
|
|
||||||
#------- RPC operation
|
#------- RPC operation
|
||||||
|
|
||||||
|
|
@ -248,10 +248,10 @@ new "limit rpc netconf ok"
|
||||||
expecteof "$clixon_netconf -U wilma -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><example xmlns="urn:example:clixon"><x>0</x></example></rpc>]]>]]>' '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><x xmlns="urn:example:clixon">0</x><y xmlns="urn:example:clixon">42</y></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -U wilma -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><example xmlns="urn:example:clixon"><x>0</x></example></rpc>]]>]]>' '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><x xmlns="urn:example:clixon">0</x><y xmlns="urn:example:clixon">42</y></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new2 "guest rpc fail"
|
new2 "guest rpc fail"
|
||||||
expecteq "$(curl -u guest:bar -s -X POST http://localhost/restconf/operations/clixon-example:example -d '{"clixon-example:input":{"x":42}}' )" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "access denied"}}}
'
|
expecteq "$(curl -u guest:bar -s -X POST http://localhost/restconf/operations/clixon-example:example -d '{"clixon-example:input":{"x":42}}' )" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "access denied"}}}
'
|
||||||
|
|
||||||
new "guest rpc netconf fail"
|
new "guest rpc netconf fail"
|
||||||
expecteof "$clixon_netconf -U guest -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><example xmlns="urn:example:clixon"><x>0</x></example></rpc>]]>]]>' '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><rpc-error><error-type>protocol</error-type><error-tag>access-denied</error-tag><error-severity>error</error-severity><error-message>access denied</error-message></rpc-error></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -U guest -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><example xmlns="urn:example:clixon"><x>0</x></example></rpc>]]>]]>' '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><rpc-error><error-type>application</error-type><error-tag>access-denied</error-tag><error-severity>error</error-severity><error-message>access denied</error-message></rpc-error></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
#------------------ Set read-default permit
|
#------------------ Set read-default permit
|
||||||
|
|
||||||
|
|
@ -267,7 +267,7 @@ expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data/nacm-exa
|
||||||
'
|
'
|
||||||
|
|
||||||
new2 "guest read state fail"
|
new2 "guest read state fail"
|
||||||
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/clixon-example:state)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/clixon-example:state)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
||||||
|
|
||||||
|
|
||||||
new "Kill restconf daemon"
|
new "Kill restconf daemon"
|
||||||
|
|
|
||||||
|
|
@ -184,7 +184,7 @@ MSG="<data>$RULES</data>"
|
||||||
new "update root list permit"
|
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")" ''
|
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"
|
new2 "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"}}}
'
|
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"
|
new "delete root permit"
|
||||||
|
|
|
||||||
|
|
@ -171,20 +171,20 @@ expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/nacm-exam
|
||||||
|
|
||||||
# Rule 1: deny-kill-session
|
# Rule 1: deny-kill-session
|
||||||
new "deny-kill-session: limited fail (netconf)"
|
new "deny-kill-session: limited fail (netconf)"
|
||||||
expecteof "$clixon_netconf -qf $cfg -U wilma" 0 "<rpc><kill-session><session-id>44</session-id></kill-session></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>protocol</error-type><error-tag>access-denied</error-tag><error-severity>error</error-severity><error-message>access denied</error-message></rpc-error></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -U wilma" 0 "<rpc><kill-session><session-id>44</session-id></kill-session></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>access-denied</error-tag><error-severity>error</error-severity><error-message>access denied</error-message></rpc-error></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "deny-kill-session: guest fail (netconf)"
|
new "deny-kill-session: guest fail (netconf)"
|
||||||
expecteof "$clixon_netconf -qf $cfg -U guest" 0 "<rpc><kill-session><session-id>44</session-id></kill-session></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>protocol</error-type><error-tag>access-denied</error-tag><error-severity>error</error-severity><error-message>access denied</error-message></rpc-error></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -U guest" 0 "<rpc><kill-session><session-id>44</session-id></kill-session></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>access-denied</error-tag><error-severity>error</error-severity><error-message>access denied</error-message></rpc-error></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "deny-kill-session: admin ok (netconf)"
|
new "deny-kill-session: admin ok (netconf)"
|
||||||
expecteof "$clixon_netconf -qf $cfg -U andy" 0 "<rpc><kill-session><session-id>44</session-id></kill-session></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -U andy" 0 "<rpc><kill-session><session-id>44</session-id></kill-session></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
# Rule 2: deny-delete-config
|
# Rule 2: deny-delete-config
|
||||||
new "deny-delete-config: limited fail (netconf)"
|
new "deny-delete-config: limited fail (netconf)"
|
||||||
expecteof "$clixon_netconf -qf $cfg -U wilma" 0 "<rpc><delete-config><target><startup/></target></delete-config></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>protocol</error-type><error-tag>access-denied</error-tag><error-severity>error</error-severity><error-message>access denied</error-message></rpc-error></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -U wilma" 0 "<rpc><delete-config><target><startup/></target></delete-config></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>access-denied</error-tag><error-severity>error</error-severity><error-message>access denied</error-message></rpc-error></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new2 "deny-delete-config: guest fail (restconf)"
|
new2 "deny-delete-config: guest fail (restconf)"
|
||||||
expecteq "$(curl -u guest:bar -sS -X DELETE http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
expecteq "$(curl -u guest: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"}}}
'
|
||||||
|
|
||||||
# In restconf delete-config is translated to edit-config which is permitted
|
# In restconf delete-config is translated to edit-config which is permitted
|
||||||
new "deny-delete-config: limited fail (restconf) ok"
|
new "deny-delete-config: limited fail (restconf) ok"
|
||||||
|
|
@ -212,7 +212,7 @@ new "permit-edit-config: limited ok restconf"
|
||||||
expecteq "$(curl -u wilma:bar -sS -X PUT -d '{"nacm-example:x": 2}' http://localhost/restconf/data/nacm-example:x)" ''
|
expecteq "$(curl -u wilma:bar -sS -X PUT -d '{"nacm-example:x": 2}' http://localhost/restconf/data/nacm-example:x)" ''
|
||||||
|
|
||||||
new2 "permit-edit-config: guest fail restconf"
|
new2 "permit-edit-config: guest fail restconf"
|
||||||
expecteq "$(curl -u guest:bar -sS -X PUT -d '{"nacm-example:x": 2}' http://localhost/restconf/data/nacm-example:x)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
expecteq "$(curl -u guest:bar -sS -X PUT -d '{"nacm-example:x": 2}' http://localhost/restconf/data/nacm-example:x)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
||||||
|
|
||||||
new "Kill restconf daemon"
|
new "Kill restconf daemon"
|
||||||
sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue