Skip to content

Commit

Permalink
FIX remove forbidden chars restrictions in ngsi subfields
Browse files Browse the repository at this point in the history
  • Loading branch information
fgalan committed Mar 11, 2024
1 parent 2bc5287 commit 2cc2424
Show file tree
Hide file tree
Showing 9 changed files with 227 additions and 35 deletions.
3 changes: 2 additions & 1 deletion doc/manuals/orion-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -398,11 +398,12 @@ the following will be used (note that "%25" is the encoding for "%").
GET /v2/entities/E%253C01%253E
```

There are some exception cases in which the above restrictions do not apply. In particular, in the following fields:
There are some exception cases in which the above restrictions do not apply. In particular, in the following cases:

* URL parameter `q` allows the special characters needed by the [Simple Query Language](#simple-query-language)
* URL parameter `mq` allows the special characters needed by the [Simple Query Language](#simple-query-language)
* URL parameter `georel` and `coords` allow `;`
* Within `ngsi` (i.e. `id`, `type` and attribute values) in [NGSI Payload patching](#ngsi-payload-patching) (to support characters used in the JEXL expression syntax)
* Whichever attribute value which uses `TextUnrestricted` as attribute type (see [Special Attribute Types](#special-attribute-types) section)

## Identifiers syntax restrictions
Expand Down
5 changes: 3 additions & 2 deletions src/lib/jsonParseV2/parseContextAttribute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,8 @@ std::string parseContextAttribute
ConnectionInfo* ciP,
const rapidjson::Value::ConstMemberIterator& iter,
ContextAttribute* caP,
bool checkAttrSpecialTypes
bool checkAttrSpecialTypes,
bool relaxForbiddenCheck
)
{
std::string name = iter->name.GetString();
Expand Down Expand Up @@ -383,7 +384,7 @@ std::string parseContextAttribute
caP->type = (compoundVector)? defaultType(orion::ValueTypeVector) : defaultType(caP->valueType);
}

std::string r = caP->check(ciP->apiVersion, ciP->requestType);
std::string r = caP->check(ciP->apiVersion, ciP->requestType, relaxForbiddenCheck);
if (r != "OK")
{
alarmMgr.badInput(clientIp, "JSON Parse Error", r);
Expand Down
3 changes: 2 additions & 1 deletion src/lib/jsonParseV2/parseContextAttribute.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ extern std::string parseContextAttribute
ConnectionInfo* ciP,
const rapidjson::Value::ConstMemberIterator& iter,
ContextAttribute* caP,
bool checkAttrSpecialTypes
bool checkAttrSpecialTypes,
bool relaxForbiddenCheck = false
);


Expand Down
14 changes: 3 additions & 11 deletions src/lib/jsonParseV2/parseSubscription.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -525,11 +525,6 @@ static std::string parseCustomPayload
}

ngsi->id = iter->value.GetString();

if (forbiddenIdChars(V2, ngsi->id.c_str(), ""))
{
return badInput(ciP, ERROR_DESC_BAD_REQUEST_INVALID_CHAR_ENTID);
}
}
else if (name == "type")
{
Expand All @@ -539,19 +534,16 @@ static std::string parseCustomPayload
}

ngsi->type = iter->value.GetString();

if (forbiddenIdChars(V2, ngsi->type.c_str(), ""))
{
return badInput(ciP, ERROR_DESC_BAD_REQUEST_INVALID_CHAR_ENTTYPE);
}
}
else // attribute
{
ContextAttribute* caP = new ContextAttribute();

ngsi->attributeVector.push_back(caP);

std::string r = parseContextAttribute(ciP, iter, caP, false);
// Note we are using relaxForbiddenCheck true in this case, as JEXL expressions typically use forbidden
// chars and we don't want to fail in that case
std::string r = parseContextAttribute(ciP, iter, caP, false, true);

if (r == "max deep reached")
{
Expand Down
6 changes: 3 additions & 3 deletions src/lib/ngsi/ContextAttribute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1363,7 +1363,7 @@ void ContextAttribute::addToContext(ExprContextObject* exprContextObjectP, bool
*
* ContextAttribute::check -
*/
std::string ContextAttribute::check(ApiVersion apiVersion, RequestType requestType)
std::string ContextAttribute::check(ApiVersion apiVersion, RequestType requestType, bool relaxForbiddenCheck)
{
size_t len;
char errorMsg[128];
Expand Down Expand Up @@ -1414,14 +1414,14 @@ std::string ContextAttribute::check(ApiVersion apiVersion, RequestType requestTy
return "Invalid characters in attribute type";
}

if ((compoundValueP != NULL) && (compoundValueP->childV.size() != 0) && (type != TEXT_UNRESTRICTED_TYPE))
if ((!relaxForbiddenCheck) && (compoundValueP != NULL) && (compoundValueP->childV.size() != 0) && (type != TEXT_UNRESTRICTED_TYPE))
{
return compoundValueP->check("");
}

if (valueType == orion::ValueTypeString)
{
if ((type != TEXT_UNRESTRICTED_TYPE) && (forbiddenChars(stringValue.c_str())))
if ((!relaxForbiddenCheck) && (type != TEXT_UNRESTRICTED_TYPE) && (forbiddenChars(stringValue.c_str())))
{
alarmMgr.badInput(clientIp, "found a forbidden character in the value of an attribute", stringValue);
return "Invalid characters in attribute value";
Expand Down
2 changes: 1 addition & 1 deletion src/lib/ngsi/ContextAttribute.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ typedef struct ContextAttribute
/* Helper method to be use in some places wher '%s' is needed */
std::string getValue(void) const;

std::string check(ApiVersion apiVersion, RequestType requestType);
std::string check(ApiVersion apiVersion, RequestType requestType, bool relaxForbiddenCheck = false);
ContextAttribute* clone();
bool compoundItemExists(const std::string& compoundPath, orion::CompoundValueNode** compoundItemPP = NULL);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ payload='{
"ngsi": {
"cal": {
"value": "${a[.b<5]}",
"type": "TextUnrestricted"
"type": "Calculated"
}
}
},
Expand Down Expand Up @@ -179,7 +179,7 @@ Fiware-Correlator: REGEX([0-9a-f\-]{36})
=====================================================================================================
POST http://127.0.0.1:REGEX(\d+)/notify
Fiware-Servicepath: /
Content-Length: 151
Content-Length: 145
User-Agent: orion/REGEX(\d+\.\d+\.\d+.*)
Ngsiv2-Attrsformat: normalized
Host: 127.0.0.1:REGEX(\d+)
Expand All @@ -192,7 +192,7 @@ Fiware-Correlator: REGEX([0-9a-f\-]{36}); cbnotif=1
{
"cal": {
"metadata": {},
"type": "TextUnrestricted",
"type": "Calculated",
"value": [
{
"b": 1
Expand All @@ -211,7 +211,7 @@ Fiware-Correlator: REGEX([0-9a-f\-]{36}); cbnotif=1
=======================================
POST http://127.0.0.1:REGEX(\d+)/notify
Fiware-Servicepath: /
Content-Length: 138
Content-Length: 132
User-Agent: orion/REGEX(\d+\.\d+\.\d+.*)
Ngsiv2-Attrsformat: normalized
Host: 127.0.0.1:REGEX(\d+)
Expand All @@ -224,7 +224,7 @@ Fiware-Correlator: REGEX([0-9a-f\-]{36}); cbnotif=1
{
"cal": {
"metadata": {},
"type": "TextUnrestricted",
"type": "Calculated",
"value": null
},
"id": "E1",
Expand All @@ -236,7 +236,7 @@ Fiware-Correlator: REGEX([0-9a-f\-]{36}); cbnotif=1
=======================================
POST http://127.0.0.1:REGEX(\d+)/notify
Fiware-Servicepath: /
Content-Length: 138
Content-Length: 132
User-Agent: orion/REGEX(\d+\.\d+\.\d+.*)
Ngsiv2-Attrsformat: normalized
Host: 127.0.0.1:REGEX(\d+)
Expand All @@ -249,7 +249,7 @@ Fiware-Correlator: REGEX([0-9a-f\-]{36}); cbnotif=1
{
"cal": {
"metadata": {},
"type": "TextUnrestricted",
"type": "Calculated",
"value": null
},
"id": "E1",
Expand All @@ -261,7 +261,7 @@ Fiware-Correlator: REGEX([0-9a-f\-]{36}); cbnotif=1
=======================================
POST http://127.0.0.1:REGEX(\d+)/notify
Fiware-Servicepath: /
Content-Length: 150
Content-Length: 144
User-Agent: orion/REGEX(\d+\.\d+\.\d+.*)
Ngsiv2-Attrsformat: normalized
Host: 127.0.0.1:REGEX(\d+)
Expand All @@ -274,7 +274,7 @@ Fiware-Correlator: REGEX([0-9a-f\-]{36}); cbnotif=1
{
"cal": {
"metadata": {},
"type": "TextUnrestricted",
"type": "Calculated",
"value": [
{
"b": -1,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
# Copyright 2024 Telefonica Investigacion y Desarrollo, S.A.U
#
# This file is part of Orion Context Broker.
#
# Orion Context Broker is free software: you can redistribute it and/or
# modify it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# Orion Context Broker is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
# General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with Orion Context Broker. If not, see http://www.gnu.org/licenses/.
#
# For those usages not covered by this license please contact with
# iot_support at tid dot es

# VALGRIND_READY - to mark the test ready for valgrindTestSuite.sh

--NAME--
JEXL expression in custom notification (using transformation in id and type)

--SHELL-INIT--
dbInit CB
brokerStart CB
accumulatorStart --pretty-print

--SHELL--

#
# 01. Create custom sub with custom expression id=S|substring(0,2), type=S|substring(3,5)
# 02. Create entity E with S=E1:T1, A:1
# 03. Update entity E with S=E2:T2, A:2
# 04. Dump accumulator and see notifications (E1/T1 A:1, E2/T2 A:2)
#


echo "01. Create custom sub with custom expression id=S|substring(0,2), type=S|substring(3,5)"
echo "======================================================================================="
payload='{
"subject": {
"entities": [
{
"id" : "E",
"type": "T"
}
]
},
"notification": {
"httpCustom": {
"url": "http://127.0.0.1:'${LISTENER_PORT}'/notify",
"ngsi": {
"id": "${S|substring(0,2)}",
"type": "${S|substring(3,5)}"
}
},
"attrs": [ "A" ]
}
}'
orionCurl --url /v2/subscriptions --payload "$payload"
echo
echo


echo "02. Create entity E with S=E1:T1, A:1"
echo "====================================="
payload='{
"id": "E",
"type": "T",
"S": {
"value": "E1:T1",
"type": "Text"
},
"A": {
"value": 1,
"type": "Number"
}
}'
orionCurl --url /v2/entities --payload "$payload"
echo
echo


echo "03. Update entity E with S=E2:T2, A:2"
echo "====================================="
payload='{
"S": {
"value": "E2:T2",
"type": "Text"
},
"A": {
"value": 2,
"type": "Number"
}
}'
orionCurl --url /v2/entities/E/attrs --payload "$payload"
echo
echo


echo "04. Dump accumulator and see notifications (E1/T1 A:1, E2/T2 A:2)"
echo "================================================================="
accumulatorDump
echo
echo


--REGEXPECT--
01. Create custom sub with custom expression id=S|substring(0,2), type=S|substring(3,5)
=======================================================================================
HTTP/1.1 201 Created
Date: REGEX(.*)
Fiware-Correlator: REGEX([0-9a-f\-]{36})
Location: /v2/subscriptions/REGEX([0-9a-f]{24})
Content-Length: 0



02. Create entity E with S=E1:T1, A:1
=====================================
HTTP/1.1 201 Created
Date: REGEX(.*)
Fiware-Correlator: REGEX([0-9a-f\-]{36})
Location: /v2/entities/E?type=T
Content-Length: 0



03. Update entity E with S=E2:T2, A:2
=====================================
HTTP/1.1 204 No Content
Date: REGEX(.*)
Fiware-Correlator: REGEX([0-9a-f\-]{36})



04. Dump accumulator and see notifications (E1/T1 A:1, E2/T2 A:2)
=================================================================
POST http://127.0.0.1:REGEX(\d+)/notify
Fiware-Servicepath: /
Content-Length: 124
User-Agent: orion/REGEX(\d+\.\d+\.\d+.*)
Ngsiv2-Attrsformat: normalized
Host: 127.0.0.1:REGEX(\d+)
Accept: application/json
Content-Type: application/json; charset=utf-8
Fiware-Correlator: REGEX([0-9a-f\-]{36}); cbnotif=1

{
"data": [
{
"A": {
"metadata": {},
"type": "Number",
"value": 1
},
"id": "E1",
"type": "T1"
}
],
"subscriptionId": "REGEX([0-9a-f]{24})"
}
=======================================
POST http://127.0.0.1:REGEX(\d+)/notify
Fiware-Servicepath: /
Content-Length: 124
User-Agent: orion/REGEX(\d+\.\d+\.\d+.*)
Ngsiv2-Attrsformat: normalized
Host: 127.0.0.1:REGEX(\d+)
Accept: application/json
Content-Type: application/json; charset=utf-8
Fiware-Correlator: REGEX([0-9a-f\-]{36}); cbnotif=1

{
"data": [
{
"A": {
"metadata": {},
"type": "Number",
"value": 2
},
"id": "E2",
"type": "T2"
}
],
"subscriptionId": "REGEX([0-9a-f]{24})"
}
=======================================


--TEARDOWN--
brokerStop CB
dbDrop CB
accumulatorStop
Loading

0 comments on commit 2cc2424

Please sign in to comment.