* Added CLICON_ANONYMOUS_USER to clicon-config.yang

* evhtp restconf closes session on -1 fatal error (no hang)
* restconf auth-type=none call ca_auth callback
* main example for auth_type=none uses basic auth to get user but without passwd check
This commit is contained in:
Olof hagsand 2021-02-21 14:48:12 +01:00
parent f97b03efc8
commit 3d07db24d9
7 changed files with 454 additions and 33 deletions

View file

@ -62,6 +62,9 @@ Users may have to change how they access the system
* New clixon-lib@2020-12-30.yang revision * New clixon-lib@2020-12-30.yang revision
* Changed: RPC process-control output parameter status to pid * Changed: RPC process-control output parameter status to pid
* New clixon-config@2020-12-30.yang revision * New clixon-config@2020-12-30.yang revision
* Added CLICON_ANONYMOUS_USER
* Only applies to restconf
* used to be hardcoded as "none", now default value is "anonymous"
* Removed obsolete RESTCONF and SSL options (CLICON_SSL_* and CLICON_RESTCONF_IP*/HTTP*) * Removed obsolete RESTCONF and SSL options (CLICON_SSL_* and CLICON_RESTCONF_IP*/HTTP*)
* Removed obsolete: CLICON_TRANSACTION_MOD option * Removed obsolete: CLICON_TRANSACTION_MOD option
* Marked as obsolete: CLICON_RESTCONF_PATH CLICON_RESTCONF_PRETTY * Marked as obsolete: CLICON_RESTCONF_PATH CLICON_RESTCONF_PRETTY

View file

@ -457,7 +457,7 @@ restconf_drop_privileges(clicon_handle h,
return -1; return -1;
} }
if (group_name2gid(group, &gid) < 0){ if (group_name2gid(group, &gid) < 0){
clicon_log(LOG_ERR, "'%s' does not seem to be a valid user group.\n" /* \n required here due to multi-line log */ clicon_log(LOG_ERR, "'%s' does not seem to be a valid user group." /* \n required here due to multi-line log */
"The config demon requires a valid group to create a server UNIX socket\n" "The config demon requires a valid group to create a server UNIX socket\n"
"Define a valid CLICON_SOCK_GROUP in %s or via the -g option\n" "Define a valid CLICON_SOCK_GROUP in %s or via the -g option\n"
"or create the group and add the user to it. Check documentation for how to do this on your platform", "or create the group and add the user to it. Check documentation for how to do this on your platform",
@ -516,24 +516,30 @@ restconf_authentication_cb(clicon_handle h,
char *username = NULL; char *username = NULL;
cxobj *xret = NULL; cxobj *xret = NULL;
cxobj *xerr; cxobj *xerr;
char *anonymous = NULL;
auth_type = restconf_auth_type_get(h); auth_type = restconf_auth_type_get(h);
clicon_debug(1, "%s auth-type:%s", __FUNCTION__, clixon_auth_type_int2str(auth_type)); clicon_debug(1, "%s auth-type:%s", __FUNCTION__, clixon_auth_type_int2str(auth_type));
ret = 0; ret = 0;
authenticated = 0; authenticated = 0;
if (auth_type != CLIXON_AUTH_NONE) /* ret: -1 Error, 0: Ignore/not handled, 1: OK see authenticated parameter */
if ((ret = clixon_plugin_auth_all(h, req, if ((ret = clixon_plugin_auth_all(h, req,
auth_type, auth_type,
&authenticated, &authenticated,
&username)) < 0) &username)) < 0)
goto done; goto done;
if (ret == 1){ /* OK, tag username to handle */ if (ret == 1){ /* OK, tag username to handle */
clicon_username_set(h, username); if (authenticated == 1)
clicon_username_set(h, username);
} }
else { /* Default behaviour */ else { /* Default behaviour */
switch (auth_type){ switch (auth_type){
case CLIXON_AUTH_NONE: case CLIXON_AUTH_NONE:
clicon_username_set(h, "none"); /* if not handled by callback, use anonymous user */
if ((anonymous = clicon_option_str(h, "CLICON_ANONYMOUS_USER")) == NULL){
break; /* not authenticated */
}
clicon_username_set(h, anonymous);
authenticated = 1; authenticated = 1;
break; break;
case CLIXON_AUTH_CLIENT_CERTIFICATE: { case CLIXON_AUTH_CLIENT_CERTIFICATE: {

View file

@ -451,6 +451,7 @@ static void
cx_path_wellknown(evhtp_request_t *req, cx_path_wellknown(evhtp_request_t *req,
void *arg) void *arg)
{ {
int retval = -1;
cx_evhtp_handle *eh = (cx_evhtp_handle*)arg; cx_evhtp_handle *eh = (cx_evhtp_handle*)arg;
clicon_handle h = eh->eh_h; clicon_handle h = eh->eh_h;
int ret; int ret;
@ -472,17 +473,32 @@ cx_path_wellknown(evhtp_request_t *req,
/* Clear (fcgi) paramaters from this request */ /* Clear (fcgi) paramaters from this request */
if (restconf_param_del_all(h) < 0) if (restconf_param_del_all(h) < 0)
goto done; goto done;
retval = 0;
done: done:
/* Catch all on fatal error. This does not terminate the process but closes request stream */
if (retval < 0)
evhtp_send_reply(req, EVHTP_RES_ERROR);
return; /* void */ return; /* void */
} }
/*! /restconf callback /*! Callback for each incoming http request for path /
*
* This are all messages except /.well-known, Registered with evhtp_set_cb
*
* @param[in] req evhtp request structure defining the incoming message
* @param[in] arg cx_evhtp handle clixon specific fields
* @retval void
* Discussion: problematic if fatal error -1 is returneod from clixon routines
* without actually terminating. Consider:
* 1) sending some error? and/or
* 2) terminating the process?
* @see cx_genb * @see cx_genb
*/ */
static void static void
cx_path_restconf(evhtp_request_t *req, cx_path_restconf(evhtp_request_t *req,
void *arg) void *arg)
{ {
int retval = -1;
cx_evhtp_handle *eh = (cx_evhtp_handle*)arg; cx_evhtp_handle *eh = (cx_evhtp_handle*)arg;
clicon_handle h = eh->eh_h; clicon_handle h = eh->eh_h;
int ret; int ret;
@ -505,13 +521,17 @@ cx_path_restconf(evhtp_request_t *req,
if (ret == 1){ if (ret == 1){
/* call generic function */ /* call generic function */
if (api_root_restconf(h, req, qvec) < 0) if (api_root_restconf(h, req, qvec) < 0)
goto done; goto done;
} }
/* Clear (fcgi) paramaters from this request */ /* Clear (fcgi) paramaters from this request */
if (restconf_param_del_all(h) < 0) if (restconf_param_del_all(h) < 0)
goto done; goto done;
retval = 0;
done: done:
/* Catch all on fatal error. This does not terminate the process but closes request stream */
if (retval < 0)
evhtp_send_reply(req, EVHTP_RES_ERROR);
if (qvec) if (qvec)
cvec_free(qvec); cvec_free(qvec);
return; /* void */ return; /* void */

View file

@ -52,8 +52,6 @@
#include <clixon/clixon_restconf.h> /* minor use */ #include <clixon/clixon_restconf.h> /* minor use */
/* Command line options to be passed to getopt(3) /* Command line options to be passed to getopt(3)
* -a basic authentication
* -s ssl client certificates
*/ */
#define RESTCONF_EXAMPLE_OPTS "" #define RESTCONF_EXAMPLE_OPTS ""
@ -194,16 +192,16 @@ b64_decode(const char *src,
* @param[out] authp 0: Credentials failed, no user set (401 returned). 1: Credentials OK and user set * @param[out] authp 0: Credentials failed, no user set (401 returned). 1: Credentials OK and user set
* @param[out] userp If retval is OK and auth=1, the associated user, malloced by plugin * @param[out] userp If retval is OK and auth=1, the associated user, malloced by plugin
* @retval -1 Fatal error * @retval -1 Fatal error
* @retval 0 OK, see auth parameter on result. * @retval 0 Ignore, undecided, not handled, same as no callback
* @retval 1 OK, see auth parameter on result.
* @note user should be malloced * @note user should be malloced
* @note: Three hardwired users: andy, wilma, guest w password "bar". * @note: Three hardwired users: andy, wilma, guest w password "bar".
* Enabled by passing -- -a to the main function
*/ */
static int static int
example_basic_auth(clicon_handle h, example_basic_auth(clicon_handle h,
void *req, void *req,
int *authp, int *authp,
char **userp) char **userp)
{ {
int retval = -1; int retval = -1;
cxobj *xt = NULL; cxobj *xt = NULL;
@ -242,7 +240,7 @@ example_basic_auth(clicon_handle h,
*passwd = '\0'; *passwd = '\0';
passwd++; passwd++;
clicon_debug(1, "%s http user:%s passwd:%s", __FUNCTION__, user, passwd); clicon_debug(1, "%s http user:%s passwd:%s", __FUNCTION__, user, passwd);
/* Here get auth sub-tree whjere all the users are */ /* Here get auth sub-tree where all the users are */
if ((cb = cbuf_new()) == NULL) if ((cb = cbuf_new()) == NULL)
goto done; goto done;
/* XXX Three hardcoded user/passwd (from RFC8341 A.1)*/ /* XXX Three hardcoded user/passwd (from RFC8341 A.1)*/
@ -252,11 +250,10 @@ example_basic_auth(clicon_handle h,
} }
if (strcmp(passwd, passwd2)) if (strcmp(passwd, passwd2))
goto fail; goto fail;
/* authenticated */ *userp = user; /* authenticated */
*userp = user;
user=NULL; /* to avoid free below */ user=NULL; /* to avoid free below */
*authp = 1; *authp = 1;
retval = 0; retval = 1;
done: /* error */ done: /* error */
clicon_debug(1, "%s retval:%d authp:%d userp:%s", __FUNCTION__, retval, *authp, *userp); clicon_debug(1, "%s retval:%d authp:%d userp:%s", __FUNCTION__, retval, *authp, *userp);
if (user) if (user)
@ -268,7 +265,78 @@ example_basic_auth(clicon_handle h,
return retval; return retval;
fail: /* unauthenticated */ fail: /* unauthenticated */
*authp = 0; *authp = 0;
retval = 0; retval = 1;
goto done;
}
/*! HTTP "no auth" but uses basic authentication to get a user
* @param[in] h Clicon handle
* @param[in] req Per-message request www handle to use with restconf_api.h
* @param[out] authp 0: Credentials failed, no user set (401 returned). 1: Credentials OK and user set
* @param[out] userp If retval is OK and auth=1, the associated user, malloced by plugin
* @retval -1 Fatal error
* @retval 0 Ignore, undecided, not handled, same as no callback
* @retval 1 OK, see auth parameter on result.
* @note user should be malloced
*/
static int
example_no_auth(clicon_handle h,
void *req,
int *authp,
char **userp)
{
int retval = -1;
cxobj *xt = NULL;
char *user = NULL;
cbuf *cb = NULL;
char *auth;
char *passwd;
size_t authlen;
int ret;
clicon_debug(1, "%s", __FUNCTION__);
if (authp == NULL || userp == NULL){
clicon_err(OE_PLUGIN, EINVAL, "Output parameter is NULL");
goto done;
}
/* At this point in the code we must use HTTP basic authentication */
if ((auth = restconf_param_get(h, "HTTP_AUTHORIZATION")) == NULL)
goto fail;
if (strlen(auth) < strlen("Basic "))
goto fail;
if (strncmp("Basic ", auth, strlen("Basic ")))
goto fail;
auth += strlen("Basic ");
authlen = strlen(auth)*2;
if ((user = malloc(authlen)) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
goto done;
}
memset(user, 0, authlen);
if ((ret = b64_decode(auth, user, authlen)) < 0)
goto done;
/* auth string is on the format user:passwd */
if ((passwd = index(user,':')) == NULL)
goto fail;
*passwd = '\0';
passwd++;
clicon_debug(1, "%s http user:%s passwd:%s", __FUNCTION__, user, passwd);
*userp = user; /* authenticated */
user=NULL; /* to avoid free below */
*authp = 1;
retval = 1;
done: /* error */
clicon_debug(1, "%s retval:%d authp:%d userp:%s", __FUNCTION__, retval, *authp, *userp);
if (user)
free(user);
if (cb)
cbuf_free(cb);
if (xt)
xml_free(xt);
return retval;
fail: /* unauthenticated */
*authp = 0;
retval = 0; /* Ignore use anonymous */
goto done; goto done;
} }
@ -295,16 +363,15 @@ example_restconf_credentials(clicon_handle h,
clicon_debug(1, "%s auth:%s", __FUNCTION__, clixon_auth_type_int2str(auth_type)); clicon_debug(1, "%s auth:%s", __FUNCTION__, clixon_auth_type_int2str(auth_type));
switch (auth_type){ switch (auth_type){
case CLIXON_AUTH_NONE: case CLIXON_AUTH_NONE:
/* Shouldnt happen */ if ((retval = example_no_auth(h, req, authp, userp)) < 0)
retval = 0; /* Ignore, shouldnt happen */ goto done;
break; break;
case CLIXON_AUTH_CLIENT_CERTIFICATE: case CLIXON_AUTH_CLIENT_CERTIFICATE:
retval = 0; /* Ignore, use default */ retval = 0; /* Ignore, use default */
break; break;
case CLIXON_AUTH_USER: case CLIXON_AUTH_USER:
if (example_basic_auth(h, req, authp, userp) < 0) if ((retval = example_basic_auth(h, req, authp, userp)) < 0)
goto done; goto done;
retval = 1;
break; break;
} }
done: done:
@ -369,8 +436,6 @@ static clixon_plugin_api api = {
* @retval NULL Error with clicon_err set * @retval NULL Error with clicon_err set
* @retval api Pointer to API struct * @retval api Pointer to API struct
* Arguments are argc/argv after -- * Arguments are argc/argv after --
* Currently defined: -a enable http basic authentication
* @note There are three hardwired users andy, wilma and guest from RFC8341 A.1
*/ */
clixon_plugin_api * clixon_plugin_api *
clixon_plugin_init(clicon_handle h) clixon_plugin_init(clicon_handle h)

View file

@ -89,7 +89,7 @@ EOF
) )
fi fi
# Start with common config, then append fcgi/evhtp specific config # Clixon config
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
@ -149,7 +149,6 @@ function testrun()
stop_restconf_pre stop_restconf_pre
new "start restconf daemon" new "start restconf daemon"
echo "cfg:$cfg"
start_restconf -f $cfg start_restconf -f $cfg
fi fi

318
test/test_restconf_basic_auth.sh Executable file
View file

@ -0,0 +1,318 @@
#!/usr/bin/env bash
# Restconf basic authentication tests as implemented by main example
# Note this is not supported by core clixon: you need ca-auth callback implemented a la the example
# For auth-type=none and auth-type=user,
# For auth-type=ssl-certs, See test_restconf.sh test_restconf_ssl_certs.sh
# evhtp? and http only
# Use the following user settings:
# 1. none (eg no -u to curl)
# 2. anonymous - the registered anonymous user
# 3. andy - a well-known user
# 3. unknown - unknown user
# Use NACM to return XML for different returns for anonymous and andy
# Magic line must be first in script (see README.md)
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
APPNAME=example
# Common NACM scripts
. ./nacm.sh
cfg=$dir/conf.xml
# The anonymous user
anonymous=myanonymous
fyang=$dir/myexample.yang
# No ssl
RCPROTO=http
# Start with common config, then append fcgi/evhtp specific config
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_FEATURE>ietf-netconf:startup</CLICON_FEATURE>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
<CLICON_BACKEND_REGEXP>example_backend.so$</CLICON_BACKEND_REGEXP>
<CLICON_RESTCONF_DIR>/usr/local/lib/$APPNAME/restconf</CLICON_RESTCONF_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
<CLICON_XMLDB_DIR>$dir</CLICON_XMLDB_DIR>
<CLICON_MODULE_LIBRARY_RFC7895>true</CLICON_MODULE_LIBRARY_RFC7895>
<CLICON_NACM_MODE>internal</CLICON_NACM_MODE>
<CLICON_ANONYMOUS_USER>$anonymous</CLICON_ANONYMOUS_USER>
</clixon-config>
EOF
# Start with common config, then append fcgi/evhtp specific config
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_FEATURE>ietf-netconf:startup</CLICON_FEATURE>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
<CLICON_BACKEND_REGEXP>example_backend.so$</CLICON_BACKEND_REGEXP>
<CLICON_RESTCONF_DIR>/usr/local/lib/$APPNAME/restconf</CLICON_RESTCONF_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
<CLICON_XMLDB_DIR>$dir</CLICON_XMLDB_DIR>
<CLICON_MODULE_LIBRARY_RFC7895>true</CLICON_MODULE_LIBRARY_RFC7895>
<CLICON_NACM_MODE>internal</CLICON_NACM_MODE>
<CLICON_ANONYMOUS_USER>$anonymous</CLICON_ANONYMOUS_USER>
</clixon-config>
EOF
# There are two implicit modules defined by RFC 8341
# This is a try to define them
cat <<EOF > $fyang
module myexample{
yang-version 1.1;
namespace "urn:example:auth";
import ietf-netconf-acm {
prefix nacm;
}
prefix ex;
container top {
leaf anonymous{
type string;
}
leaf wilma {
type string;
}
}
}
EOF
# NACM rules and top/ config
cat <<EOF > $dir/startup_db
<config>
<nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm">
<enable-nacm>true</enable-nacm>
<read-default>deny</read-default>
<write-default>deny</write-default>
<exec-default>deny</exec-default>
<groups>
<group>
<name>anonymous</name>
<user-name>$anonymous</user-name>
</group>
<group>
<name>limited</name>
<user-name>wilma</user-name>
</group>
<group>
<name>admin</name>
<user-name>root</user-name>
<user-name>$USER</user-name>
</group>
</groups>
<rule-list>
<name>data-anon</name>
<group>anonymous</group>
<rule>
<name>allow-get</name>
<module-name>ietf-netconf</module-name>
<rpc-name>get</rpc-name>
<access-operations>exec</access-operations>
<action>permit</action>
</rule>
<rule>
<name>allow-anon</name>
<module-name>myexample</module-name>
<access-operations>*</access-operations>
<path xmlns:ex="urn:example:auth">/ex:top/ex:anonymous</path>
<action>permit</action>
</rule>
</rule-list>
<rule-list>
<name>data-limited</name>
<group>limited</group>
<rule>
<name>allow-get</name>
<module-name>ietf-netconf</module-name>
<rpc-name>get</rpc-name>
<access-operations>exec</access-operations>
<action>permit</action>
</rule>
<rule>
<name>allow-wilma</name>
<module-name>myexample</module-name>
<access-operations>*</access-operations>
<path xmlns:ex="urn:example:auth">/ex:top/ex:wilma</path>
<action>permit</action>
</rule>
</rule-list>
$NADMIN
</nacm>
<top xmlns="urn:example:auth">
<anonymous>42</anonymous>
<wilma>71</wilma>
</top>
</config>
EOF
# Restconf auth test with arguments:
# 1. auth-type
# 2: -u user:passwd or ""
# 3: expectcode expected HTTP return code
# 4: expectmsg top return JSON message
# The return cases are: authentication permit/deny, authorization permit/deny
# We use authorization returns here only to verify we got the right user in authentication.
# Authentication ok/nok
# permit: 200 or 403
# deny: 401
# The user replies are:
# $anonymous: {"myexample:top":{"anonymous":"42"}}
# wilma: {"myexample:top":{"wilma":"71"}}
# unknown: retval 403
function testrun()
{
auth=$1
user=$2
expectcode=$3
expectmsg=$4
# echo "auth:$auth"
# echo "user:$user"
# echo "expectcode:$expectcode"
# echo "expectmsg:$expectmsg"
# Change restconf configuration before start restconf daemon
restconf_config $auth false
# Start with common config, then append fcgi/evhtp specific config
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_FEATURE>ietf-netconf:startup</CLICON_FEATURE>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
<CLICON_BACKEND_REGEXP>example_backend.so$</CLICON_BACKEND_REGEXP>
<CLICON_RESTCONF_DIR>/usr/local/lib/$APPNAME/restconf</CLICON_RESTCONF_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
<CLICON_XMLDB_DIR>$dir</CLICON_XMLDB_DIR>
<CLICON_MODULE_LIBRARY_RFC7895>true</CLICON_MODULE_LIBRARY_RFC7895>
<CLICON_NACM_MODE>internal</CLICON_NACM_MODE>
<CLICON_ANONYMOUS_USER>$anonymous</CLICON_ANONYMOUS_USER>
$RESTCONFIG
</clixon-config>
EOF
if [ $RC -ne 0 ]; then
new "kill old restconf daemon"
stop_restconf_pre
new "start restconf daemon"
start_restconf -f $cfg
new "wait restconf"
wait_restconf
fi
new "curl $CURLOPTS $user -X GET $RCPROTO://localhost/restconf/data/myexample:top"
expectpart "$(curl $CURLOPTS $user -X GET $RCPROTO://localhost/restconf/data/myexample:top)" 0 $expectcode "$expectmsg"
if [ $RC -ne 0 ]; then
new "Kill restconf daemon"
stop_restconf
fi
}
if [ $BE -ne 0 ]; then
new "kill old backend"
sudo clixon_backend -zf $cfg
if [ $? -ne 0 ]; then
err
fi
sudo pkill -f clixon_backend # to be sure
new "start backend -s startup -f $cfg"
start_backend -s startup -f $cfg
new "wait backend"
wait_backend
fi
MSGANON='{"myexample:top":{"anonymous":"42"}}'
MSGWILMA='{"myexample:top":{"wilma":"71"}}'
# Authentication failed:
MSGERR1='{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"access-denied","error-severity":"error","error-message":"The requested URL was unauthorized"}}}'
# Authentication OK Authorization failed:
MSGERR2='{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"default deny"}}}'
AUTH=none
new "auth-type=$AUTH no user"
testrun $AUTH "" "HTTP/1.1 200 OK" "$MSGANON" # OK - anonymous
new "auth-type=$AUTH anonymous"
testrun $AUTH "-u ${anonymous}:foo" "HTTP/1.1 200 OK" "$MSGANON" # OK - anonymous
new "auth-type=$AUTH wilma"
testrun $AUTH "-u wilma:bar" "HTTP/1.1 200 OK" "$MSGWILMA" # OK - wilma
new "auth-type=$AUTH wilma wrong passwd"
testrun $AUTH "-u wilma:wrong" "HTTP/1.1 200 OK" "$MSGWILMA" # OK - wilma
new "auth-type=$AUTH unknown"
testrun $AUTH "-u unknown:any" "HTTP/1.1 403 Forbidden" "$MSGERR2" # OK, but nacm authorization fail
AUTH=user
new "auth-type=$AUTH no user"
testrun $AUTH "" "HTTP/1.1 401 Unauthorized" "$MSGERR1" # denied
new "auth-type=$AUTH anonymous"
testrun $AUTH "-u ${anonymous}:foo" "HTTP/1.1 401 Unauthorized" "$MSGERR1" # denied
new "auth-type=$AUTH wilma"
testrun $AUTH "-u wilma:bar" "HTTP/1.1 200 OK" "$MSGWILMA" # OK - wilma
new "auth-type=$AUTH wilma wrong passwd"
testrun $AUTH "-u wilma:wrong" "HTTP/1.1 401 Unauthorized" "$MSGERR1" # denied
new "auth-type=$AUTH unknown"
testrun $AUTH "-u unknown:any" "HTTP/1.1 401 Unauthorized" "$MSGERR1" # denied
if [ $BE -ne 0 ]; then
new "Kill backend"
# Check if premature kill
pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then
err "backend already dead"
fi
# kill backend
stop_backend -f $cfg
fi
# unset conditional parameters
unset RCPROTO
unset RESTCONFIG1
unset MSGANON
unset MSGWILMA
unset MSGERR1
unset MSGERR2
rm -rf $dir

View file

@ -45,7 +45,9 @@ module clixon-config {
revision 2020-12-30 { revision 2020-12-30 {
description description
"Removed obsolete options: "Added option:
CLICON_ANONYMOUS_USER
Removed obsolete options:
CLICON_RESTCONF_IPV4_ADDR CLICON_RESTCONF_IPV4_ADDR
CLICON_RESTCONF_IPV6_ADDR CLICON_RESTCONF_IPV6_ADDR
CLICON_RESTCONF_HTTP_PORT CLICON_RESTCONF_HTTP_PORT
@ -787,6 +789,14 @@ module clixon-config {
type startup_mode; type startup_mode;
description "Which method to boot/start clicon backend"; description "Which method to boot/start clicon backend";
} }
leaf CLICON_ANONYMOUS_USER {
type string;
default "anonymous";
description
"Name of anonymous user.
The current only case where such a user is used is in RESTCONF authentication when
auth-type=none and no known user is known.";
}
leaf CLICON_NACM_MODE { leaf CLICON_NACM_MODE {
type nacm_mode; type nacm_mode;
default disabled; default disabled;