Added REST query parser
authorSachin Agrawal <sachin.agrawal@intel.com>
Mon, 15 Jun 2015 18:48:01 +0000 (11:48 -0700)
committerSachin Agrawal <sachin.agrawal@intel.com>
Mon, 15 Jun 2015 20:11:39 +0000 (20:11 +0000)
Implemented rest query parser and added unit test for the parser's API.
Also added code to handle query in Doxm resource.

Change-Id: Id3dc6c171d9faa25a44849b316eaa54171a997a6
Signed-off-by: Shilpa Sodani <shilpa.a.sodani@intel.com>
Signed-off-by: Sachin Agrawal <sachin.agrawal@intel.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/1216
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
resource/csdk/security/SConscript
resource/csdk/security/include/internal/srmresourcestrings.h
resource/csdk/security/include/srmutility.h
resource/csdk/security/provisioning/src/provisioningmanager.c
resource/csdk/security/src/doxmresource.c
resource/csdk/security/src/resourcemanager.c
resource/csdk/security/src/srmresourcestrings.c
resource/csdk/security/src/srmutility.c [new file with mode: 0644]
resource/csdk/security/unittest/SConscript
resource/csdk/security/unittest/doxmresource.cpp
resource/csdk/security/unittest/srmutility.cpp [new file with mode: 0644]

index 24b4be1..57d39a3 100644 (file)
@@ -40,6 +40,7 @@ if target_os == 'arduino':
 ######################################################################
 libocsrm_env.PrependUnique(CPPPATH = [
                '../../../extlibs/cjson/',
+#              '../../../extlibs/tinydtls/',
                '../logger/include',
                '../ocrandom/include',
                '../stack/include',
@@ -90,6 +91,7 @@ libocsrm_src = [
        OCSRM_SRC + 'policyengine.c',
        OCSRM_SRC + 'psinterface.c',
        OCSRM_SRC + 'srmresourcestrings.c',
+       OCSRM_SRC + 'srmutility.c',
        OCSRM_SRC + 'base64.c'
        ]
 
index 51f3720..794358e 100644 (file)
@@ -87,5 +87,11 @@ extern const char * RANDOM_DEVICE_PIN;
 extern const char * PRE_PROVISIONED_DEVICE_PIN;
 extern const char * PRE_PROVISIONED_STRONG_CREDENTIAL;
 
+extern const char * OIC_SEC_TRUE;
+extern const char * OIC_SEC_FALSE;
+
+extern const char * OIC_SEC_REST_QUERY_SEPARATOR;
+extern char OIC_SEC_REST_QUERY_DELIMETER;
+
 #endif //IOTVT_SRM_RSRC_STRINGS_H
 
index 34f3237..d811e25 100644 (file)
 #define IOTVT_SRM_UTILITY_H
 
 #include "ocstack.h"
-#include "uthash.h"
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+#include "uri.h"
+#ifdef __cplusplus
+}
+#endif
+
 
 #ifdef __cplusplus
 extern "C" {
 #endif // __cplusplus
 
+
+typedef struct OicParseQueryIter OicParseQueryIter_t;
+
+/**
+ * @brief   OicRestQueryIter data structure is used for book-keeping
+ *          sub-REST query's attribute's and value's, starting location &
+ *          length between calls to GetNextQuery(). This struct needs
+ *          to be first initialized with ParseQueryIterInit().
+ *
+ */
+struct OicParseQueryIter
+{
+    unsigned char * attrPos;    /**<stating location of attribute */
+    size_t attrLen;             /**<length of the attribute */
+    unsigned char * valPos;     /**<starting location of value*/
+    size_t valLen;              /**<length of the value*/
+    coap_parse_iterator_t pi;   /**<coap struct for tokenizing the query*/
+};
+
 /**
  * @def VERIFY_SUCCESS
  * @brief Macro to verify success of operation.
@@ -48,6 +75,27 @@ extern "C" {
 #define VERIFY_NON_NULL(tag, arg, logLevel) { if (NULL == (arg)) \
             { OC_LOG((logLevel), tag, PCF(#arg " is NULL")); goto exit; } }
 
+/**
+ * This method initializes the OicParseQueryIter_t struct
+ *
+ *@param query     - REST query, to be parsed
+ *@param parseIter - OicParseQueryIter_t struct, to be initialized
+ *
+ */
+void ParseQueryIterInit(unsigned char * query, OicParseQueryIter_t * parseIter);
+
+
+/**
+ * This method fills the OicParseQueryIter_t struct with next REST query's
+ * attribute's and value's information
+ *
+ *@param parseIter - OicParseQueryIter_t struct, has next query's attribute's & value's info
+ *
+ * @retval
+ *     OicParseQueryIter_t *  - has parsed query info
+ *     NULL                   - has no query to parse
+ */
+OicParseQueryIter_t * GetNextQuery(OicParseQueryIter_t * parseIter);
 
 #ifdef __cplusplus
 }
index 997374d..5a15297 100644 (file)
@@ -823,7 +823,7 @@ static void SPRequestHandler(const CARemoteEndpoint_t *object, const CARequestIn
  */
 static SPResult findResource(unsigned short timeout)
 {
-    static char DOXM_OWNED_FALSE_MULTICAST_QUERY[] = "/oic/sec/doxm?Owned=\"FALSE\"";
+    static char DOXM_OWNED_FALSE_MULTICAST_QUERY[] = "/oic/sec/doxm?Owned=FALSE";
     CAResult_t res = CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN);
     if (CA_STATUS_OK != res)
     {
index aa7380f..99f420c 100755 (executable)
@@ -34,7 +34,6 @@
 #include "credresource.h"
 #include "ocserverrequest.h"
 #include "srmutility.h"
-#include "uthash.h"
 #include <stdlib.h>
 #include <string.h>
 
@@ -325,21 +324,75 @@ static bool UpdatePersistentStorage(OicSecDoxm_t * doxm)
     return bRet;
 }
 
+static bool ValidateQuery(unsigned char * query)
+{
+    // Send doxm resource data if the state of doxm resource
+    // matches with the query parameters.
+    // else send doxm resource data as NULL
+    // TODO Remove this check and rely on Policy Engine
+    // and Provisioning Mode to enforce provisioning-state
+    // access rules. Eventually, the PE and PM code will
+    // not send a request to the /doxm Entity Handler at all
+    // if it should not respond.
+    OC_LOG (INFO, TAG, PCF("In ValidateQuery"));
+    if(NULL == gDoxm)
+    {
+        return false;
+    }
+
+    OicParseQueryIter_t parseIter = {};
+
+    ParseQueryIterInit(query, &parseIter);
+
+    while(GetNextQuery(&parseIter))
+    {
+        if(strncasecmp((char *)parseIter.attrPos, OIC_JSON_OWNED_NAME, parseIter.attrLen) == 0)
+        {
+            if((strncasecmp((char *)parseIter.valPos, OIC_SEC_TRUE, parseIter.valLen) == 0) &&
+                    (gDoxm->owned))
+            {
+                return true;
+            }
+            else if((strncasecmp((char *)parseIter.valPos, OIC_SEC_FALSE, parseIter.valLen) == 0)
+                    && (!gDoxm->owned))
+            {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
 static OCEntityHandlerResult HandleDoxmGetRequest (const OCEntityHandlerRequest * ehRequest)
 {
-    // Convert Doxm data into JSON for transmission
-    char* jsonStr = BinToDoxmJSON(gDoxm);
+    char* jsonStr = NULL;
+    OCEntityHandlerResult ehRet = OC_EH_OK;
+
+    OC_LOG (INFO, TAG, PCF("Doxm EntityHandle processing GET request"));
+
+    //Checking if Get request is a query.
+    if(ehRequest->query)
+    {
+        OC_LOG (INFO, TAG, PCF("HandleDoxmGetRequest processing query"));
+        if(!ValidateQuery((unsigned char *)ehRequest->query))
+        {
+            ehRet = OC_EH_ERROR;
+        }
+    }
 
     /*
-     * A device should 'always' have a default Doxm. Therefore,
-     * jsonStr should never be NULL.
+     * For GET or Valid Query request return doxm resource json payload.
+     * For non-valid query return NULL json payload.
+     * A device will 'always' have a default Doxm, so BinToDoxmJSON will
+     * return valid doxm resource json.
      */
-    OCEntityHandlerResult ehRet = (jsonStr ? OC_EH_OK : OC_EH_ERROR);
+
+    jsonStr = (ehRet == OC_EH_OK) ? BinToDoxmJSON(gDoxm) : NULL;
 
     // Send response payload to request originator
     if(OC_STACK_OK != SendSRMResponse(ehRequest, ehRet, jsonStr))
     {
-        OC_LOG (ERROR, TAG, PCF("SendSRMResponse failed in HandlePstatGetRequest"));
+        OC_LOG (ERROR, TAG, PCF("SendSRMResponse failed in HandleDoxmGetRequest"));
     }
 
     OICFree(jsonStr);
@@ -350,6 +403,7 @@ static OCEntityHandlerResult HandleDoxmGetRequest (const OCEntityHandlerRequest
 
 static OCEntityHandlerResult HandleDoxmPutRequest (const OCEntityHandlerRequest * ehRequest)
 {
+    OC_LOG (INFO, TAG, PCF("Doxm EntityHandle  processing PUT request"));
     OCEntityHandlerResult ehRet = OC_EH_ERROR;
     OicUuid_t emptyOwner = {};
 
@@ -371,6 +425,7 @@ static OCEntityHandlerResult HandleDoxmPutRequest (const OCEntityHandlerRequest
              */
             if ((false == gDoxm->owned) && (false == newDoxm->owned))
             {
+                OC_LOG (INFO, TAG, PCF("Doxm EntityHandle  enabling AnonECDHCipherSuite"));
 #ifdef __WITH_DTLS__
                 ehRet = (CAEnableAnonECDHCipherSuite(true) == CA_STATUS_OK) ? OC_EH_OK : OC_EH_ERROR;
 #endif //__WITH_DTLS__
@@ -398,6 +453,7 @@ static OCEntityHandlerResult HandleDoxmPutRequest (const OCEntityHandlerRequest
                 uint8_t ownerPSK[OWNER_PSK_LENGTH_128] = {};
 
                 //Generating OwnerPSK
+                OC_LOG (INFO, TAG, PCF("Doxm EntityHandle  generating OwnerPSK"));
                 pskRet = CAGenerateOwnerPSK(&request->addressInfo,
                         request->connectivityType,
                         (uint8_t*) OXM_JUST_WORKS, strlen(OXM_JUST_WORKS),
@@ -416,6 +472,7 @@ static OCEntityHandlerResult HandleDoxmPutRequest (const OCEntityHandlerRequest
                                 sizeof(base64Buff), &outLen);
                 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
 
+                OC_LOG (INFO, TAG, PCF("Doxm EntityHandle  generating Credential"));
                 OicSecCred_t *cred = GenerateCredential(&newDoxm->owner, SYMMETRIC_PAIR_WISE_KEY,
                                         NULL, base64Buff, ownLen, &newDoxm->owner);
                 VERIFY_NON_NULL(TAG, cred, ERROR);
index 5a41bb9..64725cc 100644 (file)
@@ -43,6 +43,7 @@
 OCStackResult SendSRMResponse(const OCEntityHandlerRequest *ehRequest,
         OCEntityHandlerResult ehRet, const char *rspPayload)
 {
+    OC_LOG (INFO, TAG, PCF("SRM sending SRM response"));
     OCEntityHandlerResponse response = {};
     if (ehRequest)
     {
index 6deca6b..b9e1f3a 100644 (file)
@@ -85,3 +85,8 @@ const char * OXM_RANDOM_DEVICE_PIN = "oic.sec.doxm.rdp";
 const char * OXM_PRE_PROVISIONED_DEVICE_PIN = "oic.sec.doxm.ppdp";
 const char * OXM_PRE_PROVISIONED_STRONG_CREDENTIAL = "oic.sec.doxm.ppsc";
 
+const char * OIC_SEC_TRUE = "true";
+const char * OIC_SEC_FALSE = "false";
+
+const char * OIC_SEC_REST_QUERY_SEPARATOR = "&";
+char OIC_SEC_REST_QUERY_DELIMETER = '=';
diff --git a/resource/csdk/security/src/srmutility.c b/resource/csdk/security/src/srmutility.c
new file mode 100644 (file)
index 0000000..3f97b57
--- /dev/null
@@ -0,0 +1,86 @@
+//******************************************************************
+//
+// Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#define _POSIX_C_SOURCE 200112L
+#include <string.h>
+
+#include "srmutility.h"
+#include "srmresourcestrings.h"
+#include "logger.h"
+
+#define TAG  PCF("SRM-UTILITY")
+
+/**
+ * This method initializes the OicParseQueryIter_t struct
+ *
+ *@param query     - REST query, to be parsed
+ *@param parseIter - OicParseQueryIter_t struct, to be initialized
+ *
+ */
+void ParseQueryIterInit(unsigned char * query, OicParseQueryIter_t * parseIter)
+{
+    OC_LOG (INFO, TAG, PCF("Initializing coap iterator"));
+    if((NULL == query) || (NULL == parseIter))
+        return;
+
+    parseIter->attrPos = NULL;
+    parseIter->attrLen = 0;
+    parseIter->valPos = NULL;
+    parseIter->valLen = 0;
+    coap_parse_iterator_init(query, strlen((char *)query),
+          (unsigned char *)OIC_SEC_REST_QUERY_SEPARATOR, (unsigned char *) "", 0, &parseIter->pi);
+}
+
+
+/**
+ * This method fills the OicParseQueryIter_t struct with next REST query's
+ * attribute's and value's information
+ *
+ *@param parseIter - OicParseQueryIter_t struct, has next query's attribute's & value's info
+ *
+ * @retval
+ *     OicParseQueryIter_t *  - has parsed query info
+ *     NULL                   - has no query to parse
+ */
+OicParseQueryIter_t * GetNextQuery(OicParseQueryIter_t * parseIter)
+{
+    OC_LOG (INFO, TAG, PCF("Getting Next Query"));
+    if(NULL == parseIter)
+        return NULL;
+
+    unsigned char * qrySeg = NULL;
+    char * delimPos;
+
+    //Get the next query. Querys are separated by OIC_SEC_REST_QUERY_SEPARATOR
+    qrySeg = coap_parse_next(&parseIter->pi);
+
+    if(qrySeg)
+    {
+        delimPos = strchr((char *)qrySeg, OIC_SEC_REST_QUERY_DELIMETER);
+        if(delimPos)
+        {
+            parseIter->attrPos = parseIter->pi.pos;
+            parseIter->attrLen = (unsigned char *)delimPos - parseIter->pi.pos;
+            parseIter->valPos  = (unsigned char *)delimPos + 1;
+            parseIter->valLen  = &qrySeg[parseIter->pi.segment_length] - parseIter->valPos;
+            return parseIter;
+        }
+    }
+    return NULL;
+}
index 7aea344..d1193ac 100644 (file)
@@ -34,6 +34,7 @@ srmtest_env.PrependUnique(CPPPATH = [
                '../../connectivity/inc',
                '../../connectivity/api',
                '../../connectivity/external/inc',
+               '../../connectivity/lib/libcoap-4.1.1',
                '../include',
                '../include/internal',
                '../../logger/include',
@@ -43,6 +44,7 @@ srmtest_env.PrependUnique(CPPPATH = [
                '../../../oc_logger/include',
                '../../../../extlibs/gtest/gtest-1.7.0/include',
                '../../../../extlibs/cjson/',
+#              '../../../../extlibs/tinydtls/',
                '../include'
                ])
 srmtest_env.AppendUnique(CXXFLAGS = ['-std=c++0x', '-Wall', '-pthread'])
@@ -72,6 +74,7 @@ unittest = srmtest_env.Program('unittest', ['aclresourcetest.cpp',
                                             'policyengine.cpp',
                                             'securityresourcemanager.cpp',
                                             'credentialresource.cpp',
+                                            'srmutility.cpp',
                                             'base64tests.cpp'])
 
 Alias("test", [unittest])
index 13e03b7..0b32cd9 100644 (file)
@@ -38,6 +38,7 @@ OicSecDoxm_t * JSONToDoxmBin(const char * jsonStr);
 void InitSecDoxmInstance(OicSecDoxm_t * doxm);
 OCEntityHandlerResult HandleDoxmPostRequest (const OCEntityHandlerRequest * ehRequest);
 void DeleteDoxmBinData(OicSecDoxm_t* doxm);
+OCEntityHandlerResult HandleDoxmGetRequest (const OCEntityHandlerRequest * ehRequest);
 #ifdef __cplusplus
 }
 #endif
@@ -97,6 +98,19 @@ TEST(DoxmEntityHandlerTest, DoxmEntityHandlerInvalidFlag)
     EXPECT_EQ(OC_EH_ERROR, DoxmEntityHandler(OCEntityHandlerFlag::OC_OBSERVE_FLAG, &req));
 }
 
+TEST(DoxmEntityHandlerTest, DoxmEntityHandlerValidRequest)
+{
+    EXPECT_EQ(OC_STACK_INVALID_PARAM, InitDoxmResource());
+    char query[] = "oxm=0&owned=false&owner=owner1";
+    OCEntityHandlerRequest req = {};
+    req.method = OC_REST_GET;
+    req.query = (char*)OICMalloc(strlen(query) + 1);
+    strcpy((char *)req.query, query);
+    EXPECT_EQ(OC_EH_ERROR, DoxmEntityHandler(OCEntityHandlerFlag::OC_REQUEST_FLAG, &req));
+
+    OICFree(req.query);
+}
+
 //BinToDoxmJSON Tests
 TEST(BinToDoxmJSONTest, BinToDoxmJSONNullDoxm)
 {
@@ -136,12 +150,8 @@ TEST(JSONToDoxmBinTest, JSONToDoxmBinNullJSON)
     EXPECT_TRUE(doxm == NULL);
 }
 
-//GetDoxmResourceData Test
-TEST(DoxmGetResourceDataTest, GetDoxmResourceData)
-{
-    EXPECT_TRUE(NULL == GetDoxmResourceData());
-}
 #if 0
+//HandleDoxmPostRequest Test
 TEST(HandleDoxmPostRequestTest, HandleDoxmPostRequestValidInput)
 {
     OCEntityHandlerRequest ehRequest = {};
diff --git a/resource/csdk/security/unittest/srmutility.cpp b/resource/csdk/security/unittest/srmutility.cpp
new file mode 100644 (file)
index 0000000..25c0a1f
--- /dev/null
@@ -0,0 +1,71 @@
+// Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#include "gtest/gtest.h"
+#include "ocstack.h"
+#include "srmutility.h"
+
+
+//ParseRestQuery Tests
+TEST(ParseRestQueryTest, ParseRestQueryEmpty)
+{
+    unsigned char query[] = "";
+    OicParseQueryIter_t parseIter = {};
+    ParseQueryIterInit(query, &parseIter);
+    EXPECT_EQ(NULL,  GetNextQuery(&parseIter));
+}
+
+TEST(ParseRestQueryTest, ParseSingleRestQuery)
+{
+    char attr[10], val[10];
+    unsigned char query[] = "owned=false";
+
+    OicParseQueryIter_t parseIter = {};
+    ParseQueryIterInit(query, &parseIter);
+    EXPECT_NE((OicParseQueryIter_t *)NULL,  GetNextQuery(&parseIter));
+
+    strncpy(attr, (char *)parseIter.attrPos, parseIter.attrLen);
+    strncpy(val, (char *)parseIter.valPos, parseIter.valLen);
+    attr[parseIter.attrLen] = '\0';
+    val[parseIter.valLen] = '\0';
+    printf("\nAttribute: %s  value: %s\n\n", attr, val);
+
+}
+
+TEST(ParseRestQueryTest, ParseRestMultipleQuery)
+{
+    char attr[10], val[10];
+    unsigned char query[] = "oxm=0&owned=true&owner=owner1";
+
+    OicParseQueryIter_t parseIter = {};
+    ParseQueryIterInit(query, &parseIter);
+    printf("\n");
+    while(GetNextQuery(&parseIter))
+    {
+        EXPECT_NE(0,  parseIter.pi.segment_length);
+
+        strncpy(attr, (char *)parseIter.attrPos, parseIter.attrLen);
+        strncpy(val, (char *)parseIter.valPos, parseIter.valLen);
+        attr[parseIter.attrLen] = '\0';
+        val[parseIter.valLen] = '\0';
+        printf("Attribute: %s  value: %s\n", attr, val);
+
+    }
+    printf("\n");
+}
+