Updated ACL & DOXM entity handler to process GET query
authorSachin Agrawal <sachin.agrawal@intel.com>
Mon, 14 Sep 2015 23:55:15 +0000 (16:55 -0700)
committerSachin Agrawal <sachin.agrawal@intel.com>
Tue, 15 Sep 2015 19:02:30 +0000 (19:02 +0000)
Updated ACL resource entity handler to process GET query
and DOXM resource entity handler to process GET query for
device ID.

Change-Id: Ia293fd633e0ce4f70202a6f80a04bd0f283510fa
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/2411
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
resource/csdk/security/src/aclresource.c
resource/csdk/security/src/doxmresource.c
resource/csdk/security/unittest/aclresourcetest.cpp
resource/csdk/security/unittest/doxmresource.cpp

index 1b858f8..e0f0937 100644 (file)
@@ -437,7 +437,7 @@ static OCStackResult RemoveACE(const OicUuid_t * subject,
     }
 
     //If resource is NULL then delete all the ACE for the subject.
-    if(NULL == resource)
+    if(NULL == resource || resource[0] == '\0')
     {
         LL_FOREACH_SAFE(gAcl, acl, tempAcl)
         {
@@ -505,16 +505,139 @@ static OCStackResult RemoveACE(const OicUuid_t * subject,
     return ret;
 }
 
+/*
+ * This method parses the query string received for REST requests and
+ * retrieves the 'subject' field.
+ *
+ * @param query querystring passed in REST request
+ * @param subject subject UUID parsed from query string
+ *
+ * @return true if query parsed successfully and found 'subject', else false.
+ */
+static bool GetSubjectFromQueryString(const char *query, OicUuid_t *subject)
+{
+    OicParseQueryIter_t parseIter = {.attrPos=NULL};
+
+    ParseQueryIterInit((unsigned char *)query, &parseIter);
+
+    while(GetNextQuery(&parseIter))
+    {
+        if(strncasecmp((char *)parseIter.attrPos, OIC_JSON_SUBJECT_NAME, parseIter.attrLen) == 0)
+        {
+            VERIFY_SUCCESS(TAG, 0 != parseIter.valLen, ERROR);
+            unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
+            uint32_t outLen = 0;
+            B64Result b64Ret = B64_OK;
+            b64Ret = b64Decode((char *)parseIter.valPos, parseIter.valLen, base64Buff,
+                    sizeof(base64Buff), &outLen);
+            VERIFY_SUCCESS(TAG, (B64_OK == b64Ret && outLen <= sizeof(subject->id)), ERROR);
+            memcpy(subject->id, base64Buff, outLen);
+
+            return true;
+        }
+    }
+
+exit:
+   return false;
+}
+
+/*
+ * This method parses the query string received for REST requests and
+ * retrieves the 'resource' field.
+ *
+ * @param query querystring passed in REST request
+ * @param resource resource parsed from query string
+ * @param resourceSize size of the memory pointed to resource
+ *
+ * @return true if query parsed successfully and found 'resource', else false.
+ */
+static bool GetResourceFromQueryString(const char *query, char *resource, size_t resourceSize)
+{
+    OicParseQueryIter_t parseIter = {.attrPos=NULL};
+
+    ParseQueryIterInit((unsigned char *)query, &parseIter);
+
+    while(GetNextQuery(&parseIter))
+    {
+        if(strncasecmp((char *)parseIter.attrPos, OIC_JSON_RESOURCES_NAME, parseIter.attrLen) == 0)
+        {
+            VERIFY_SUCCESS(TAG, 0 != parseIter.valLen, ERROR);
+            OICStrcpy(resource, resourceSize, (char *)parseIter.valPos);
+
+            return true;
+        }
+    }
+
+exit:
+   return false;
+}
+
+
+
 static OCEntityHandlerResult HandleACLGetRequest (const OCEntityHandlerRequest * ehRequest)
 {
-    // Convert ACL data into JSON for transmission
-    char* jsonStr = BinToAclJSON(gAcl);
+    OCEntityHandlerResult ehRet = OC_EH_ERROR;
+    char* jsonStr = NULL;
 
-    /*
-     * A device should 'always' have a default ACL. Therefore,
-     * jsonStr should never be NULL.
-     */
-    OCEntityHandlerResult ehRet = (jsonStr ? OC_EH_OK : OC_EH_ERROR);
+    // Process the REST querystring parameters
+    if(ehRequest->query)
+    {
+        OC_LOG (INFO, TAG, PCF("HandleACLGetRequest processing query"));
+
+        OicUuid_t subject = {.id={0}};
+        char resource[MAX_URI_LENGTH] = {0};
+
+        OicSecAcl_t *savePtr = NULL;
+        const OicSecAcl_t *currentAce = NULL;
+
+        // 'Subject' field is MUST for processing a querystring in REST request.
+        VERIFY_SUCCESS(TAG,
+                       true == GetSubjectFromQueryString(ehRequest->query, &subject),
+                       ERROR);
+
+        GetResourceFromQueryString(ehRequest->query, resource, sizeof(resource));
+
+        /*
+         * TODO : Currently, this code only provides one ACE for a Subject.
+         * Below code needs to be updated for scenarios when Subject have
+         * multiple ACE's in ACL resource.
+         */
+        while((currentAce = GetACLResourceData(&subject, &savePtr)))
+        {
+            /*
+             * If REST querystring contains a specific resource, we need
+             * to search for that resource in ACE.
+             */
+            if (resource[0] != '\0')
+            {
+                for(size_t n = 0; n < currentAce->resourcesLen; n++)
+                {
+                    if((currentAce->resources[n]) &&
+                            (0 == strcmp(resource, currentAce->resources[n]) ||
+                             0 == strcmp(WILDCARD_RESOURCE_URI, currentAce->resources[n])))
+                    {
+                        // Convert ACL data into JSON for transmission
+                        jsonStr = BinToAclJSON(currentAce);
+                        goto exit;
+                    }
+                }
+            }
+            else
+            {
+                // Convert ACL data into JSON for transmission
+                jsonStr = BinToAclJSON(currentAce);
+                goto exit;
+            }
+        }
+    }
+    else
+    {
+        // Convert ACL data into JSON for transmission
+        jsonStr = BinToAclJSON(gAcl);
+    }
+
+exit:
+    ehRet = (jsonStr ? OC_EH_OK : OC_EH_ERROR);
 
     // Send response payload to request originator
     SendSRMResponse(ehRequest, ehRet, jsonStr);
@@ -554,50 +677,27 @@ static OCEntityHandlerResult HandleACLDeleteRequest(const OCEntityHandlerRequest
 {
     OC_LOG (INFO, TAG, PCF("Processing ACLDeleteRequest"));
     OCEntityHandlerResult ehRet = OC_EH_ERROR;
-
-    if(NULL == ehRequest->query)
-    {
-        return ehRet;
-    }
-    OicParseQueryIter_t parseIter = {.attrPos=NULL};
     OicUuid_t subject = {.id={0}};
-    char * resource = NULL;
+    char resource[MAX_URI_LENGTH] = {0};
 
-    //Parsing REST query to get subject & resource
-    ParseQueryIterInit((unsigned char *)ehRequest->query, &parseIter);
+    VERIFY_NON_NULL(TAG, ehRequest->query, ERROR);
 
-    while(GetNextQuery(&parseIter))
-    {
-        if(strncasecmp((char *)parseIter.attrPos, OIC_JSON_SUBJECT_NAME, parseIter.attrLen) == 0)
-        {
-            unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
-            uint32_t outLen = 0;
-            B64Result b64Ret = B64_OK;
+    // 'Subject' field is MUST for processing a querystring in REST request.
+    VERIFY_SUCCESS(TAG,
+            true == GetSubjectFromQueryString(ehRequest->query, &subject),
+            ERROR);
 
-           b64Ret = b64Decode((char *)parseIter.valPos, parseIter.valLen, base64Buff,
-                               sizeof(base64Buff), &outLen);
-
-           VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(subject.id)), ERROR);
-           memcpy(subject.id, base64Buff, outLen);
-        }
-        if(strncasecmp((char *)parseIter.attrPos, OIC_JSON_RESOURCES_NAME, parseIter.attrLen) == 0)
-        {
-            resource = (char *)OICMalloc(parseIter.valLen);
-            VERIFY_NON_NULL(TAG, resource, ERROR);
-            OICStrcpy(resource, sizeof(resource), (char *)parseIter.valPos);
-        }
-    }
+    GetResourceFromQueryString(ehRequest->query, resource, sizeof(resource));
 
     if(OC_STACK_RESOURCE_DELETED == RemoveACE(&subject, resource))
     {
         ehRet = OC_EH_RESOURCE_DELETED;
     }
-    OICFree(resource);
 
+exit:
     // Send payload to request originator
     SendSRMResponse(ehRequest, ehRet, NULL);
 
-exit:
     return ehRet;
 }
 
@@ -620,7 +720,7 @@ OCEntityHandlerResult ACLEntityHandler (OCEntityHandlerFlag flag,
 
     if (flag & OC_REQUEST_FLAG)
     {
-        // TODO :  Handle PUT and DEL methods
+        // TODO :  Handle PUT method
         OC_LOG (INFO, TAG, PCF("Flag includes OC_REQUEST_FLAG"));
         switch (ehRequest->method)
         {
index 78d91ba..6725151 100644 (file)
@@ -340,7 +340,7 @@ static bool UpdatePersistentStorage(OicSecDoxm_t * doxm)
     return bRet;
 }
 
-static bool ValidateQuery(unsigned char * query)
+static bool ValidateQuery(const char * query)
 {
     // Send doxm resource data if the state of doxm resource
     // matches with the query parameters.
@@ -356,27 +356,54 @@ static bool ValidateQuery(unsigned char * query)
         return false;
     }
 
+    bool bOwnedQry = false;         // does querystring contains 'owned' query ?
+    bool bOwnedMatch = false;       // does 'owned' query value matches with doxm.owned status?
+    bool bDeviceIDQry = false;      // does querystring contains 'deviceid' query ?
+    bool bDeviceIDMatch = false;    // does 'deviceid' query matches with doxm.deviceid ?
+
     OicParseQueryIter_t parseIter = {.attrPos = NULL};
 
-    ParseQueryIterInit(query, &parseIter);
+    ParseQueryIterInit((unsigned char*)query, &parseIter);
 
     while(GetNextQuery(&parseIter))
     {
         if(strncasecmp((char *)parseIter.attrPos, OIC_JSON_OWNED_NAME, parseIter.attrLen) == 0)
         {
+            bOwnedQry = true;
             if((strncasecmp((char *)parseIter.valPos, OIC_SEC_TRUE, parseIter.valLen) == 0) &&
                     (gDoxm->owned))
             {
-                return true;
+                bOwnedMatch = true;
             }
             else if((strncasecmp((char *)parseIter.valPos, OIC_SEC_FALSE, parseIter.valLen) == 0)
                     && (!gDoxm->owned))
             {
-                return true;
+                bOwnedMatch = true;
+            }
+        }
+
+        if(strncasecmp((char *)parseIter.attrPos, OIC_JSON_DEVICE_ID_NAME, parseIter.attrLen) == 0)
+        {
+            bDeviceIDQry = true;
+            OicUuid_t subject = {.id={0}};
+            unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
+            uint32_t outLen = 0;
+            B64Result b64Ret = B64_OK;
+
+            b64Ret = b64Decode((char *)parseIter.valPos, parseIter.valLen, base64Buff,
+                                           sizeof(base64Buff), &outLen);
+
+            VERIFY_SUCCESS(TAG, (B64_OK == b64Ret && outLen <= sizeof(subject.id)), ERROR);
+                       memcpy(subject.id, base64Buff, outLen);
+            if(0 == memcmp(&gDoxm->deviceID.id, &subject.id, sizeof(gDoxm->deviceID.id)))
+            {
+                bDeviceIDMatch = true;
             }
         }
     }
-    return false;
+
+exit:
+    return ((bOwnedQry ? bOwnedMatch : true) && (bDeviceIDQry ? bDeviceIDMatch : true));
 }
 
 static OCEntityHandlerResult HandleDoxmGetRequest (const OCEntityHandlerRequest * ehRequest)
@@ -390,7 +417,7 @@ static OCEntityHandlerResult HandleDoxmGetRequest (const OCEntityHandlerRequest
     if(ehRequest->query)
     {
         OC_LOG (INFO, TAG, PCF("HandleDoxmGetRequest processing query"));
-        if(!ValidateQuery((unsigned char *)ehRequest->query))
+        if(!ValidateQuery(ehRequest->query))
         {
             ehRet = OC_EH_ERROR;
         }
index 9bbca6c..6ab674c 100644 (file)
@@ -205,6 +205,35 @@ TEST(ACLResourceTest, GetACLResourceTests)
         OICFree(jsonStr);
     }
 }
+
+static OCStackResult  populateAcl(OicSecAcl_t *acl,  int numRsrc)
+{
+    OCStackResult ret = OC_STACK_ERROR;
+    memcpy(acl->subject.id, "2222222222222222", sizeof(acl->subject.id));
+    acl->resourcesLen = numRsrc;
+    acl->resources = (char**)OICCalloc(acl->resourcesLen, sizeof(char*));
+    VERIFY_NON_NULL(TAG, acl->resources, ERROR);
+    acl->resources[0] = (char*)OICMalloc(strlen("/a/led")+1);
+    VERIFY_NON_NULL(TAG, acl->resources[0], ERROR);
+    OICStrcpy(acl->resources[0], sizeof(acl->resources[0]), "/a/led");
+    if(numRsrc == 2)
+    {
+        acl->resources[1] = (char*)OICMalloc(strlen("/a/fan")+1);
+        VERIFY_NON_NULL(TAG, acl->resources[1], ERROR);
+        OICStrcpy(acl->resources[1], sizeof(acl->resources[1]), "/a/fan");
+    }
+    acl->permission = 6;
+    acl->ownersLen = 1;
+    acl->owners = (OicUuid_t*)OICCalloc(acl->ownersLen, sizeof(OicUuid_t));
+    VERIFY_NON_NULL(TAG, acl->owners, ERROR);
+    memcpy(acl->owners->id, "1111111111111111", sizeof(acl->owners->id));
+
+    ret = OC_STACK_OK;
+exit:
+    return ret;
+
+}
+
 //'DELETE' ACL test
 TEST(ACLResourceTest, ACLDeleteWithSingleResourceTest)
 {
@@ -220,19 +249,8 @@ TEST(ACLResourceTest, ACLDeleteWithSingleResourceTest)
 
     SetPersistentHandler(&ps, true);
 
-    //ACE to POST
-    memcpy(acl.subject.id, "2222222222222222", sizeof(acl.subject.id));
-    acl.resourcesLen = 1;
-    acl.resources = (char**)OICCalloc(acl.resourcesLen, sizeof(char*));
-    VERIFY_NON_NULL(TAG, acl.resources, ERROR);
-    acl.resources[0] = (char*)OICMalloc(strlen("/a/led")+1);
-    VERIFY_NON_NULL(TAG, acl.resources[0], ERROR);
-    OICStrcpy(acl.resources[0], sizeof(acl.resources[0]), "/a/led");
-    acl.permission = 6;
-    acl.ownersLen = 1;
-    acl.owners = (OicUuid_t*)OICCalloc(acl.ownersLen, sizeof(OicUuid_t));
-    VERIFY_NON_NULL(TAG, acl.owners, ERROR);
-    memcpy(acl.owners->id, "1111111111111111", sizeof(acl.owners->id));
+    //Populate ACL
+    VERIFY_SUCCESS(TAG, (OC_STACK_OK == populateAcl(&acl, 1)), ERROR);
 
     //GET json POST payload
     jsonStr = BinToAclJSON(&acl);
@@ -288,22 +306,10 @@ TEST(ACLResourceTest, ACLDeleteWithMultiResourceTest)
 
     SetPersistentHandler(&ps, true);
 
-    memcpy(acl.subject.id, "2222222222222222", sizeof(acl.subject.id));
-    acl.resourcesLen = 2;
-    acl.resources = (char**)OICCalloc(acl.resourcesLen, sizeof(char*));
-    VERIFY_NON_NULL(TAG, acl.resources, ERROR);
-    acl.resources[0] = (char*)OICMalloc(strlen("/a/led")+1);
-    VERIFY_NON_NULL(TAG, acl.resources[0], ERROR);
-    OICStrcpy(acl.resources[0], sizeof(acl.resources[0]), "/a/led");
-    acl.resources[1] = (char*)OICMalloc(strlen("/a/fan")+1);
-    VERIFY_NON_NULL(TAG, acl.resources[1], ERROR);
-    OICStrcpy(acl.resources[1], sizeof(acl.resources[1]), "/a/fan");
-    acl.permission = 6;
-    acl.ownersLen = 1;
-    acl.owners = (OicUuid_t*)OICCalloc(acl.ownersLen, sizeof(OicUuid_t));
-    VERIFY_NON_NULL(TAG, acl.owners, ERROR);
-    memcpy(acl.owners->id, "1111111111111111", sizeof(acl.owners->id));
+    //Populate ACL
+    VERIFY_SUCCESS(TAG, (OC_STACK_OK == populateAcl(&acl, 2)), ERROR);
 
+    //GET json POST payload
     jsonStr = BinToAclJSON(&acl);
     VERIFY_NON_NULL(TAG, jsonStr, ERROR);
 
@@ -345,3 +351,44 @@ exit:
     OICFree(jsonStr);
 }
 
+//'GET' with query ACL test
+
+TEST(ACLResourceTest, ACLGetWithQueryTest)
+{
+    OCEntityHandlerRequest ehReq = OCEntityHandlerRequest();
+    static OCPersistentStorage ps = OCPersistentStorage();
+    OicSecAcl_t acl = OicSecAcl_t();
+    char *jsonStr = NULL;
+    OCEntityHandlerResult ehRet = OC_EH_ERROR;
+    char query[] = "sub=MjIyMjIyMjIyMjIyMjIyMg==;rsrc=/a/led";
+
+    SetPersistentHandler(&ps, true);
+
+    //Populate ACL
+    VERIFY_SUCCESS(TAG, (OC_STACK_OK == populateAcl(&acl, 1)), ERROR);
+
+    //GET json POST payload
+    jsonStr = BinToAclJSON(&acl);
+    VERIFY_NON_NULL(TAG, jsonStr, ERROR);
+
+    //Create Entity Handler POST request payload
+    ehReq.method = OC_REST_POST;
+    ehReq.payload = (OCPayload*)OCSecurityPayloadCreate(jsonStr);
+    ehRet = ACLEntityHandler(OC_REQUEST_FLAG, &ehReq);
+    EXPECT_TRUE(OC_EH_ERROR == ehRet);
+
+    //Create Entity Handler GET request wit query
+    ehReq.method =  OC_REST_GET;
+    ehReq.query = (char*)OICMalloc(strlen(query)+1);
+    VERIFY_NON_NULL(TAG, ehReq.query, ERROR);
+    OICStrcpy(ehReq.query, strlen(query)+1, query);
+
+    ehRet = ACLEntityHandler(OC_REQUEST_FLAG, &ehReq);
+    EXPECT_TRUE(OC_EH_OK == ehRet);
+
+exit:
+    // Perform cleanup
+    OCPayloadDestroy(ehReq.payload);
+    OICFree(ehReq.query);
+    OICFree(jsonStr);
+}
index cfee71a..29ca779 100644 (file)
@@ -140,6 +140,18 @@ TEST(DoxmEntityHandlerTest, DoxmEntityHandlerValidRequest)
     OICFree(req.query);
 }
 
+TEST(DoxmEntityHandlerTest, DoxmEntityHandlerDeviceIdQuery)
+{
+    EXPECT_EQ(OC_STACK_INVALID_PARAM, InitDoxmResource());
+    char query[] = "deviceid=MjIyMjIyMjIyMjIyMjIyMg==";
+    OCEntityHandlerRequest req = OCEntityHandlerRequest();
+    req.method = OC_REST_GET;
+    req.query = OICStrdup(query);
+    EXPECT_EQ(OC_EH_ERROR, DoxmEntityHandler(OCEntityHandlerFlag::OC_REQUEST_FLAG, &req));
+
+    OICFree(req.query);
+}
+
 //BinToDoxmJSON Tests
 TEST(BinToDoxmJSONTest, BinToDoxmJSONNullDoxm)
 {