From 6b08a22f04e4a7ffb21852aa82750936564cde1a Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Wed, 10 Feb 2021 14:17:34 +0100 Subject: [PATCH] * RESTCONF failed authentication changed error return code from 403 Forbiden to 401 Unauthorized following RFC 8040 --- CHANGELOG.md | 2 ++ apps/restconf/restconf_err.c | 14 ++++++++++++++ apps/restconf/restconf_lib.c | 4 ++-- test/test_nacm.sh | 4 ++-- test/test_nacm_ext.sh | 4 ++-- 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a932817a..481fc5c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,8 @@ Expected: February 2021 ### New features +* RESTCONF failed authentication changed error return code from 403 Forbiden to 401 Unauthorized following RFC 8040 + * Authentication OK but failed on access, remains as 403 Forbidden * NETCONF Call Home Call Home RFC 8071 * See [Netconf/ssh callhome](https://clixon-docs.readthedocs.io/en/latest/netconf.html#callhome) * Solution description using openssh and utility functions, no changes to core clixon diff --git a/apps/restconf/restconf_err.c b/apps/restconf/restconf_err.c index edf719b7..591c0974 100644 --- a/apps/restconf/restconf_err.c +++ b/apps/restconf/restconf_err.c @@ -430,6 +430,20 @@ api_return_err(clicon_handle h, else{ if ((code = restconf_err2code(tagstr)) < 0) code = 500; /* internal server error */ + if (code == 403){ + /* Special case: netconf only has "access denied" while restconf + * differentiates between: + * 401 Unauthorized If the RESTCONF client is not authenticated (sec 2.5) + * 403 Forbidden If the user is not authorized to access a target resource or invoke + * an operation + */ + cxobj *xmsg; + char *mb; + if ((xmsg = xpath_first(xerr, NULL, "error-message")) != NULL && + (mb = xml_body(xmsg)) != NULL && + strcmp(mb, "The requested URL was unauthorized") == 0) + code = 401; + } } if (restconf_reply_header(req, "Content-Type", "%s", restconf_media_int2str(media)) < 0) // XXX goto done; diff --git a/apps/restconf/restconf_lib.c b/apps/restconf/restconf_lib.c index 7faa943d..6a5fcce0 100644 --- a/apps/restconf/restconf_lib.c +++ b/apps/restconf/restconf_lib.c @@ -81,8 +81,8 @@ static const map_str2int netconf_restconf_map[] = { {"bad-element", 400}, {"unknown-element", 400}, {"unknown-namespace", 400}, - {"access-denied", 403}, - {"access-denied", 401}, /* or 403 */ + {"access-denied", 403}, /* or 401 special case if tagstr is: "The requested URL was unauthorized" handled in api_return_err */ + {"access-denied", 401}, {"lock-denied", 409}, {"resource-denied", 409}, {"rollback-failed", 500}, diff --git a/test/test_nacm.sh b/test/test_nacm.sh index 721ceb7e..67bb3637 100755 --- a/test/test_nacm.sh +++ b/test/test_nacm.sh @@ -156,10 +156,10 @@ new "commit it" expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" "^]]>]]>$" new "auth get (no user: access denied)" -expectpart "$(curl $CURLOPTS -X GET -H \"Accept:\ application/yang-data+json\" $RCPROTO://localhost/restconf/data)" 0 "HTTP/1.1 403 Forbidden" '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"access-denied","error-severity":"error","error-message":"The requested URL was unauthorized"}}} ' +expectpart "$(curl $CURLOPTS -X GET -H \"Accept:\ application/yang-data+json\" $RCPROTO://localhost/restconf/data)" 0 "HTTP/1.1 401 Unauthorized" '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"access-denied","error-severity":"error","error-message":"The requested URL was unauthorized"}}} ' new "auth get (wrong passwd: access denied)" -expectpart "$(curl -u andy:foo $CURLOPTS -X GET $RCPROTO://localhost/restconf/data)" 0 "HTTP/1.1 403 Forbidden" '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"access-denied","error-severity":"error","error-message":"The requested URL was unauthorized"}}}' +expectpart "$(curl -u andy:foo $CURLOPTS -X GET $RCPROTO://localhost/restconf/data)" 0 "HTTP/1.1 401 Unauthorized" '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"access-denied","error-severity":"error","error-message":"The requested URL was unauthorized"}}}' new "auth get (access)" expectpart "$(curl -u andy:bar $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/nacm-example:x)" 0 "HTTP/1.1 200 OK" '{"nacm-example:x":0}' diff --git a/test/test_nacm_ext.sh b/test/test_nacm_ext.sh index c8d3be56..72d46f33 100755 --- a/test/test_nacm_ext.sh +++ b/test/test_nacm_ext.sh @@ -168,10 +168,10 @@ new "Set x to 0" expectpart "$(curl -u andy:bar $CURLOPTS -X PUT -H "Content-Type: application/yang-data+json" -d '{"nacm-example:x": 0}' $RCPROTO://localhost/restconf/data/nacm-example:x)" 0 "HTTP/1.1 201 Created" new "auth get (no user: access denied)" -expectpart "$(curl $CURLOPTS -X GET -H \"Accept:\ application/yang-data+json\" $RCPROTO://localhost/restconf/data)" 0 "HTTP/1.1 403 Forbidden" '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"access-denied","error-severity":"error","error-message":"The requested URL was unauthorized"}}}' +expectpart "$(curl $CURLOPTS -X GET -H \"Accept:\ application/yang-data+json\" $RCPROTO://localhost/restconf/data)" 0 "HTTP/1.1 401 Unauthorized" '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"access-denied","error-severity":"error","error-message":"The requested URL was unauthorized"}}}' new "auth get (wrong passwd: access denied)" -expectpart "$(curl -u andy:foo $CURLOPTS -X GET $RCPROTO://localhost/restconf/data)" 0 "HTTP/1.1 403 Forbidden" '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"access-denied","error-severity":"error","error-message":"The requested URL was unauthorized"}}}' +expectpart "$(curl -u andy:foo $CURLOPTS -X GET $RCPROTO://localhost/restconf/data)" 0 "HTTP/1.1 401 Unauthorized" '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"access-denied","error-severity":"error","error-message":"The requested URL was unauthorized"}}}' new "auth get (access)" expectpart "$(curl -u andy:bar $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/nacm-example:x)" 0 "HTTP/1.1 200 OK" '{"nacm-example:x":0}'