Added AMS functionality to support on-demand ACL provisioning.
authorSachin Agrawal <sachin.agrawal@intel.com>
Sun, 20 Sep 2015 00:31:39 +0000 (17:31 -0700)
committerSachin Agrawal <sachin.agrawal@intel.com>
Sun, 20 Sep 2015 01:28:49 +0000 (01:28 +0000)
This change includes the new "AMS Manager" (amsmgr.c) module, as well
as modifications to the SRM proper, policy engine, and doxmresource,
which are required to enable Access Management Service functionality in
the SRM.

Change-Id: Ibf10e00bebeeafd238ac083c7d45c1bbf7a46dd3
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/2486
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
20 files changed:
resource/csdk/security/SConscript
resource/csdk/security/include/internal/aclresource.h
resource/csdk/security/include/internal/amaclresource.h
resource/csdk/security/include/internal/amsmgr.h [new file with mode: 0644]
resource/csdk/security/include/internal/policyengine.h
resource/csdk/security/include/internal/secureresourcemanager.h
resource/csdk/security/include/securevirtualresourcetypes.h
resource/csdk/security/src/aclresource.c
resource/csdk/security/src/amaclresource.c
resource/csdk/security/src/amsmgr.c [new file with mode: 0644]
resource/csdk/security/src/policyengine.c
resource/csdk/security/src/secureresourcemanager.c
resource/csdk/security/unittest/policyengine.cpp
resource/csdk/stack/samples/linux/secure/README [new file with mode: 0644]
resource/csdk/stack/samples/linux/secure/SConscript
resource/csdk/stack/samples/linux/secure/ocamsservice.cpp [new file with mode: 0644]
resource/csdk/stack/samples/linux/secure/oic_amss_db.json [new file with mode: 0644]
resource/csdk/stack/samples/linux/secure/oic_svr_db_server.json
resource/provisioning/examples/SConscript
resource/provisioning/unittests/SConscript

index cf7ad92..c00caba 100755 (executable)
@@ -48,10 +48,11 @@ libocsrm_env.PrependUnique(CPPPATH = [
                '../../oc_logger/include',
                '../connectivity/lib/libcoap-4.1.1',
                '../connectivity/external/inc',
+               '../connectivity/common/inc',
                '../connectivity/inc',
                '../connectivity/api',
                '../security/include',
-               '../security/include/internal',
+               '../security/include/internal'
                ])
 
 if target_os not in ['arduino', 'windows', 'winrt']:
@@ -88,6 +89,7 @@ if env.get('SECURED') == '1':
                OCSRM_SRC + 'resourcemanager.c',
                OCSRM_SRC + 'aclresource.c',
                OCSRM_SRC + 'amaclresource.c',
+               OCSRM_SRC + 'amsmgr.c',
                OCSRM_SRC + 'pstatresource.c',
                OCSRM_SRC + 'doxmresource.c',
                OCSRM_SRC + 'credresource.c',
@@ -109,6 +111,7 @@ else:
                OCSRM_SRC + 'resourcemanager.c',
                OCSRM_SRC + 'aclresource.c',
                OCSRM_SRC + 'amaclresource.c',
+               OCSRM_SRC + 'amsmgr.c',
                OCSRM_SRC + 'pstatresource.c',
                OCSRM_SRC + 'doxmresource.c',
                OCSRM_SRC + 'credresource.c',
index 216fbd5..564d23f 100644 (file)
@@ -62,6 +62,7 @@ const OicSecAcl_t* GetACLResourceData(const OicUuid_t* subjectId, OicSecAcl_t **
  */
 char* BinToAclJSON(const OicSecAcl_t * acl);
 
+
 /**
  * This function deletes ACL data.
  *
@@ -69,6 +70,16 @@ char* BinToAclJSON(const OicSecAcl_t * acl);
  */
 void DeleteACLList(OicSecAcl_t* acl);
 
+
+/**
+ * This function installs a new ACL.
+ * @param newJsonStr JSON string representing a new ACL.
+ *
+ * @retval  OC_STACK_OK for Success, otherwise some error value
+ */
+OCStackResult InstallNewACL(const char* newJsonStr);
+
+
 #ifdef __cplusplus
 }
 #endif
index e1f4f5b..9c37a0e 100755 (executable)
@@ -48,17 +48,19 @@ OCStackResult InitAmaclResource();
 void DeInitAmaclResource();
 
 /**
- * This method is used by PolicyEngine to retrieve Amacl for a Subject.
+ * This method is used by PolicyEngine to retrieve amsId for the resource.
+ * If the Amacl is found for the given resource then populate the parameter
+ * amsId with Amacl resource amss id.
  *
- * @param subjectId ID of the subject for which Amacl is required.
- * @param savePtr is used internally by @ref GetAmaclResourceData to maintain index between
- *                successive calls for same subjectId.
+ * @param resource  resource for which AMS service is required.
+ * @param amsId     ID of the ams service for the given resource
  *
- * @retval  reference to @ref OicSecAmacl_t if Amacl is found, else NULL
+ * @retval
+ *  OC_STACK_OK     If Amacl found for the resource
+ *  OC_STACK_ERROR  If no Amacl found for the resource
  *
- * @note On the first call to @ref GetAmaclResourceData, savePtr should point to NULL
  */
-const OicSecAmacl_t* GetAmaclResourceData(const OicUuid_t* subjectId, OicSecAmacl_t **savePtr);
+OCStackResult AmaclGetAmsDeviceId(const char *resource, OicUuid_t *amsId);
 
 /**
  * This function converts Amacl data into JSON format.
diff --git a/resource/csdk/security/include/internal/amsmgr.h b/resource/csdk/security/include/internal/amsmgr.h
new file mode 100644 (file)
index 0000000..c83530f
--- /dev/null
@@ -0,0 +1,135 @@
+//******************************************************************
+//
+// 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.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#ifndef IOTVT_SRM_AMSMGR_H
+#define IOTVT_SRM_AMSMGR_H
+
+#include "ocstack.h"
+#include "logger.h"
+#include "policyengine.h"
+#include "securevirtualresourcetypes.h"
+#include "cainterface.h"
+#include <stdlib.h>
+#include <stdint.h>
+
+typedef struct PEContext PEContext_t;
+/**
+ * @brief   The AMS context..
+ */
+typedef struct AmsMgrContext
+{
+    OicUuid_t           amsDeviceId;  /**< DeviceID of the oic.sec.ams service. */
+    CAEndpoint_t        *endpoint;
+    CARequestInfo_t     *requestInfo;
+} AmsMgrContext_t;
+
+
+/**
+ * @brief This method updates AmsMgr context's endpoint & requestInfo
+ *
+ * @param context          Policy engine context.
+ * @param endpoint         CA Endpoint info of the requester
+ * @param requestInfo      CA RequestInfo of the requester
+ */
+OCStackResult UpdateAmsMgrContext(PEContext_t *context, const CAEndpoint_t *endpoint,
+                       const CARequestInfo_t *requestInfo);
+
+/**
+ *
+ * This method is called by PolicyEngine to Discover AMS service.
+ * It sends muticast discovery request such as
+ * /oic/sec/doxm?deviceid="AMSSrvcDeviceID" to discover AMS service
+ * with deviceId="AMSSrvcDeviceID"
+ *
+ * @param context   Policy engine context.
+ *
+ * @retval
+ *  OC_STACK_OK     If able to successfully send multicast discovery request.
+ *  OC_STACK_ERROR  If unable to successfully send multicast discovery request due to error.
+ *
+ */
+OCStackResult DiscoverAmsService(PEContext_t *context);
+
+
+/**
+ *
+ * This method sends unicast request to retrieve the secured port info of the
+ * discovered AMS service. It sends unicast discovery request such as
+ * /oic/res?rt="oic.sec.doxm" to the discovered AMS service
+ *
+ * @param context   Policy engine context.
+ *
+ * @retval
+ *  OC_STACK_OK     If able to successfully send unicast discovery request
+ *  OC_STACK_ERROR  If unable to successfully send unicast discovery request due to error
+ *
+ */
+OCStackResult SendUnicastSecurePortDiscovery(PEContext_t *context,OCDevAddr *devAddr,
+                                      OCConnectivityType connType);
+
+
+/**
+ *
+ * This method sends unicast request to AMS service to get ACL for
+ * the Subject and/or Resource. It sends unicast request such as
+ * /oic/sec/acl?sub="subjectId";rsrc="/a/led" to get the ACL for
+ * the subject & resource
+ *
+ * @param context   Policy engine context.
+ *
+ * @retval
+ *  OC_STACK_OK     If able to successfully send unicast ACL request
+ *  OC_STACK_ERROR  If unable to successfully send unicast ACL request due to error
+ *
+ */
+OCStackResult SendAclReq(PEContext_t *context, OCDevAddr *devAddr, OCConnectivityType connType,
+        uint16_t securedPort);
+
+
+/*
+ * Cleanup CARequestInfo_t object
+ * @param requestInfo        pointer to RequestInfo_t object
+ */
+void FreeCARequestInfo(CARequestInfo_t *requestInfo);
+
+
+/*
+ * This method is used by Policy engine to checks Amacl resource.
+ * If Amacl is found then it fills up context->amsMgrContext->amsDeviceId
+ * with amsID of the Amacl else leaves it empty.
+ *
+ * @param context   Policy engine context.
+ *
+ * @return          true if AMacl for the resource is found
+ *                  false if AMacl for the resource is not found
+ */
+bool FoundAmaclForRequest(PEContext_t *context);
+
+
+/*
+ * This method is used by Policy engine to process AMS request
+ * *
+ * @param context   Policy engine context.
+ *
+ * @return          None
+ */
+void ProcessAMSRequest(PEContext_t *context);
+
+#endif //IOTVT_SRM_AMSMGR_H
index a792bfa..ba40d68 100644 (file)
 #include "logger.h"
 #include "securevirtualresourcetypes.h"
 #include "cainterface.h"
+#include "amsmgr.h"
 #include <stdlib.h>
 #include <stdint.h>
 
+typedef struct AmsMgrContext AmsMgrContext_t;
+
 
 typedef enum PEState
 {
-    STOPPED = 0,
-    AWAITING_REQUEST,
-    BUSY
+    STOPPED = 0,              //Policy engine state machine is not running
+    AWAITING_REQUEST,         //Can process new request
+    AWAITING_AMS_RESPONSE,    //Can't process new request; waiting for AMS response
+    BUSY                      //Can't process new request as processing other requests
 } PEState_t;
 
+
 typedef struct PEContext
 {
     PEState_t   state;
-    OicUuid_t   *subject;
-    char        *resource;
+    OicUuid_t   subject;
+    char        resource[MAX_URI_LENGTH];
     uint16_t    permission;
     bool        matchingAclFound;
+    bool        amsProcessing;
     SRMAccessResponse_t retVal;
+    AmsMgrContext_t     *amsMgrContext;
 } PEContext_t;
 
 /**
@@ -85,4 +92,16 @@ void DeInitPolicyEngine(PEContext_t *context);
  */
 uint16_t GetPermissionFromCAMethod_t(const CAMethod_t method);
 
+
+/*
+ * This method reset Policy Engine context to default state and update
+ * it's state to @param state.
+ *
+ * @param context  Policy engine context.
+ * @param state    Set Policy engine state to this.
+ *
+ * @return         none
+ */
+void SetPolicyEngineState(PEContext_t *context, const PEState_t state);
+
 #endif //IOTVT_SRM_PE_H
index 6fc5b42..6505acc 100644 (file)
@@ -21,6 +21,8 @@
 #ifndef SECURITYRESOURCEMANAGER_H_
 #define SECURITYRESOURCEMANAGER_H_
 
+#include "securevirtualresourcetypes.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -94,6 +96,15 @@ typedef bool (*SPResponseCallback) (const CAEndpoint_t *object,
  */
 void SRMRegisterProvisioningResponseHandler(SPResponseCallback respHandler);
 
+
+/**
+ * @brief   Sends Response
+ * @param   resposeVal       SRMAccessResponse_t value
+
+ * @return  NONE
+ */
+void SRMSendResponse(SRMAccessResponse_t responseVal);
+
 #ifdef __cplusplus
 }
 #endif
index 9641beb..e08cda4 100644 (file)
@@ -59,6 +59,8 @@ extern "C" {
 #define RESOURCE_NOT_FOUND_DEF        (1 << 4)
 #define POLICY_ENGINE_ERROR_DEF       (1 << 5)
 #define INVALID_PERIOD_DEF            (1 << 6)
+#define ACCESS_WAITING_DEF            (1 << 7)
+#define AMS_SERVICE_DEF               (1 << 8)
 #define REASON_MASK_DEF               (INSUFFICIENT_PERMISSION_DEF | \
                                        INVALID_PERIOD_DEF | \
                                        SUBJECT_NOT_FOUND_DEF | \
@@ -114,6 +116,10 @@ typedef enum
         | RESOURCE_NOT_FOUND_DEF,
     ACCESS_DENIED_POLICY_ENGINE_ERROR = ACCESS_DENIED_DEF
         | POLICY_ENGINE_ERROR_DEF,
+    ACCESS_WAITING_FOR_AMS = ACCESS_WAITING_DEF
+        | AMS_SERVICE_DEF,
+    ACCESS_DENIED_AMS_SERVICE_ERROR = ACCESS_DENIED
+        | AMS_SERVICE_DEF
 } SRMAccessResponse_t;
 
 /**
index 5515fc6..55058c7 100644 (file)
@@ -409,6 +409,7 @@ static bool UpdatePersistentStorage(const OicSecAcl_t *acl)
     }
     return false;
 }
+
 /*
  * This method removes ACE for the subject and resource from the ACL
  *
@@ -520,6 +521,7 @@ static bool GetSubjectFromQueryString(const char *query, OicUuid_t *subject)
 
     ParseQueryIterInit((unsigned char *)query, &parseIter);
 
+
     while(GetNextQuery(&parseIter))
     {
         if(strncasecmp((char *)parseIter.attrPos, OIC_JSON_SUBJECT_NAME, parseIter.attrLen) == 0)
@@ -969,3 +971,34 @@ const OicSecAcl_t* GetACLResourceData(const OicUuid_t* subjectId, OicSecAcl_t **
     *savePtr = NULL;
     return NULL;
 }
+
+
+OCStackResult InstallNewACL(const char* newJsonStr)
+{
+    OCStackResult ret = OC_STACK_ERROR;
+
+    // Convert JSON ACL data into binary. This will also validate the ACL data received.
+    OicSecAcl_t* newAcl = JSONToAclBin(newJsonStr);
+
+    if (newAcl)
+    {
+        // Append the new ACL to existing ACL
+        LL_APPEND(gAcl, newAcl);
+
+        // Convert ACL data into JSON for update to persistent storage
+        char *jsonStr = BinToAclJSON(gAcl);
+        if (jsonStr)
+        {
+            cJSON *jsonAcl = cJSON_Parse(jsonStr);
+            OICFree(jsonStr);
+
+            if (jsonAcl)
+            {
+                ret = UpdateSVRDatabase(OIC_JSON_ACL_NAME, jsonAcl);
+            }
+            cJSON_Delete(jsonAcl);
+        }
+    }
+
+    return ret;
+}
index e0ba0b2..ff7bdb4 100644 (file)
@@ -401,3 +401,28 @@ void DeInitAmaclResource()
     DeleteAmaclList(gAmacl);
     gAmacl = NULL;
 }
+
+
+OCStackResult AmaclGetAmsDeviceId(const char *resource, OicUuid_t *amsDeviceId)
+{
+    OicSecAmacl_t *amacl = NULL;
+
+    VERIFY_NON_NULL(TAG, resource, ERROR);
+    VERIFY_NON_NULL(TAG, amsDeviceId, ERROR);
+
+    LL_FOREACH(gAmacl, amacl)
+    {
+        for(size_t i = 0; i < amacl->resourcesLen; i++)
+        {
+            if (strncmp((amacl->resources[i]), resource, strlen(amacl->resources[i])) == 0)
+            {
+                //Returning the ID of the first AMS service for the resource
+                memcpy(amsDeviceId, &amacl->amss[0], sizeof(*amsDeviceId));
+                return OC_STACK_OK;
+            }
+        }
+    }
+
+exit:
+    return OC_STACK_ERROR;
+}
diff --git a/resource/csdk/security/src/amsmgr.c b/resource/csdk/security/src/amsmgr.c
new file mode 100644 (file)
index 0000000..365cb10
--- /dev/null
@@ -0,0 +1,423 @@
+//******************************************************************
+//
+// 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 "oic_malloc.h"
+#include "amsmgr.h"
+#include "resourcemanager.h"
+#include "securevirtualresourcetypes.h"
+#include "srmresourcestrings.h"
+#include "logger.h"
+#include "ocrandom.h"
+#include "aclresource.h"
+#include "amaclresource.h"
+#include "srmutility.h"
+#include "base64.h"
+#include "secureresourcemanager.h"
+#include "doxmresource.h"
+#include "policyengine.h"
+#include "oic_string.h"
+#include "caremotehandler.h"
+#include <string.h>
+
+#define TAG "SRM-AMSMGR"
+
+
+ //Callback for AMS service multicast discovery request.
+static OCStackApplicationResult AmsMgrDiscoveryCallback(void *ctx, OCDoHandle handle,
+                         OCClientResponse * clientResponse);
+
+//Callback for unicast secured port discovery request.
+static OCStackApplicationResult SecurePortDiscoveryCallback(void *ctx, OCDoHandle handle,
+                         OCClientResponse * clientResponse);
+
+//Callback for unicast ACL request
+static OCStackApplicationResult AmsMgrAclReqCallback(void *ctx, OCDoHandle handle,
+    OCClientResponse * clientResponse);
+
+
+OCStackResult DiscoverAmsService(PEContext_t *context)
+{
+    OC_LOG(INFO, TAG, "IN DiscoverAmsService");
+
+    OCStackResult ret = OC_STACK_ERROR;
+    const char DOXM_DEVICEID_QUERY_FMT[] = "%s?%s=%s";
+    char uri[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {};
+    OCCallbackData cbData = {.context=NULL};
+    char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {};
+    uint32_t outLen = 0;
+    B64Result b64Ret;
+
+    VERIFY_NON_NULL(TAG, context, ERROR);
+    b64Ret = b64Encode(context->amsMgrContext->amsDeviceId.id,
+          sizeof(context->amsMgrContext->amsDeviceId.id), base64Buff, sizeof(base64Buff), &outLen);
+    VERIFY_SUCCESS(TAG, B64_OK == b64Ret, ERROR);
+    snprintf(uri, sizeof(uri), DOXM_DEVICEID_QUERY_FMT, OIC_RSRC_DOXM_URI,
+                                       OIC_JSON_DEVICE_ID_NAME, base64Buff);
+
+    cbData.cb = &AmsMgrDiscoveryCallback;
+    cbData.context = (void*)context;
+
+    /* TODO
+     * If no good response was received for this discovery request,
+     * PE would be blocked forever waiting for AMS service to respond with the ACE.
+     * Need logic to reset the PE state and send ACCESS_DENIED response,
+     * when discovery response from AMS service is not received within certain time.
+     */
+    OC_LOG_V(INFO, TAG,"AMS Manager Sending Multicast Discovery with URI = %s", uri);
+    ret = OCDoResource(NULL, OC_REST_DISCOVER, uri, NULL, NULL,
+                       CT_DEFAULT, OC_LOW_QOS, &cbData, NULL, 0);
+
+exit:
+    OC_LOG(INFO, TAG, "Leaving DiscoverAmsService");
+    return ret;
+}
+
+
+static OCStackApplicationResult AmsMgrDiscoveryCallback(void *ctx, OCDoHandle handle,
+                         OCClientResponse * clientResponse)
+{
+    OC_LOG_V(INFO, TAG, "%s Begin", __func__ );
+
+    if (!ctx ||
+        !clientResponse ||
+        !clientResponse->payload||
+        (PAYLOAD_TYPE_SECURITY != clientResponse->payload->type)||
+        (OC_STACK_OK != clientResponse->result))
+    {
+        OC_LOG_V(ERROR, TAG, "%s Invalid Response ", __func__);
+        return OC_STACK_KEEP_TRANSACTION;
+    }
+
+    (void)handle;
+    PEContext_t *context = (PEContext_t *) ctx;
+    if (context->state != AWAITING_AMS_RESPONSE)
+    {
+        OC_LOG_V(ERROR, TAG, "%s Invalid PE State ", __func__);
+        return OC_STACK_DELETE_TRANSACTION;
+    }
+
+    OicSecDoxm_t *doxm = NULL;
+    OC_LOG_V(INFO, TAG, "Doxm DeviceId Discovery response = %s\n",
+          ((OCSecurityPayload*)clientResponse->payload)->securityData);
+    doxm = JSONToDoxmBin(((OCSecurityPayload*)clientResponse->payload)->securityData);
+
+    //As doxm is NULL amsmgr can't test if response from trusted AMS service
+    //so keep the transaction.
+    if(NULL == doxm)
+    {
+        OC_LOG_V(ERROR, TAG, "%s : Unable to convert JSON to Binary",__func__);
+        return OC_STACK_KEEP_TRANSACTION;
+    }
+
+    OicUuid_t deviceId = {.id={}};
+    memcpy(&deviceId, &doxm->deviceID, sizeof(deviceId));
+    OICFree(doxm);
+
+    /* TODO : By assuming that the first response received is the actual
+     * AMS service, a 'bad device' can cause DoS attack.
+     */
+    if (memcmp(&context->amsMgrContext->amsDeviceId, &deviceId,
+            sizeof(context->amsMgrContext->amsDeviceId)) == 0)
+    {
+        OC_LOG(INFO, TAG, "AMS Manager Sending unicast discovery to get secured port info");
+        //Sending Unicast discovery to get secure port information
+        if(OC_STACK_OK == SendUnicastSecurePortDiscovery(context, &clientResponse->devAddr,
+                clientResponse->connType))
+        {
+            context->retVal = ACCESS_WAITING_FOR_AMS;
+            return OC_STACK_DELETE_TRANSACTION;
+        }
+    }
+    context->retVal = ACCESS_DENIED_AMS_SERVICE_ERROR;
+    SRMSendResponse(context->retVal);
+    return OC_STACK_DELETE_TRANSACTION;
+}
+
+
+OCStackResult SendUnicastSecurePortDiscovery(PEContext_t *context,OCDevAddr *devAddr,
+                                      OCConnectivityType connType)
+{
+    OC_LOG(INFO, TAG, "IN SendUnicastSecurePortDiscovery");
+
+    const char RES_DOXM_QUERY_FMT[] = "%s?%s=%s";
+    OCCallbackData cbData = {.context=NULL};
+    char uri[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {};
+    snprintf(uri, sizeof(uri), RES_DOXM_QUERY_FMT, OC_RSRVD_WELL_KNOWN_URI,
+            OC_RSRVD_RESOURCE_TYPE, OIC_RSRC_TYPE_SEC_DOXM);
+
+    cbData.cb = &SecurePortDiscoveryCallback;
+    cbData.context = context;
+
+    OC_LOG_V(INFO, TAG, "AMS Manager Sending Unicast Discovery with URI = %s", uri);
+
+    return  OCDoResource(NULL, OC_REST_DISCOVER, uri, devAddr, NULL,
+                         connType, OC_LOW_QOS, &cbData, NULL, 0);
+}
+
+static OCStackApplicationResult SecurePortDiscoveryCallback(void *ctx, OCDoHandle handle,
+                         OCClientResponse * clientResponse)
+{
+    OC_LOG(INFO, TAG, "In SecurePortDiscoveryCallback");
+
+    if (!ctx ||
+        !clientResponse ||
+        !clientResponse->payload||
+        (PAYLOAD_TYPE_DISCOVERY != clientResponse->payload->type)||
+        (OC_STACK_OK != clientResponse->result))
+        {
+            OC_LOG_V(ERROR, TAG, "%s Invalid Response ", __func__);
+            SRMSendResponse(ACCESS_DENIED_AMS_SERVICE_ERROR);
+            return OC_STACK_DELETE_TRANSACTION;
+        }
+
+    PEContext_t *context = (PEContext_t *) ctx;
+    (void)handle;
+    if (context->state != AWAITING_AMS_RESPONSE)
+    {
+        OC_LOG_V(ERROR, TAG, "%s Invalid PE State ", __func__);
+        context->retVal = ACCESS_DENIED_AMS_SERVICE_ERROR;
+        SRMSendResponse(context->retVal);
+        return OC_STACK_DELETE_TRANSACTION;
+    }
+    OCResourcePayload* resPayload = ((OCDiscoveryPayload*)clientResponse->payload)->resources;
+
+    //Verifying if the ID of the sender is an AMS service that this device trusts.
+    if(memcmp(context->amsMgrContext->amsDeviceId.id, resPayload->sid,
+                    sizeof(context->amsMgrContext->amsDeviceId.id)) != 0)
+    {
+        context->retVal = ACCESS_DENIED_AMS_SERVICE_ERROR;
+        SRMSendResponse(context->retVal);
+        return OC_STACK_DELETE_TRANSACTION;
+    }
+
+    if (resPayload && resPayload->secure)
+    {
+        if(OC_STACK_OK == SendAclReq(context, &clientResponse->devAddr, clientResponse->connType,
+                resPayload->port))
+        {
+            return OC_STACK_DELETE_TRANSACTION;
+        }
+    }
+    OC_LOG(INFO, TAG, "Can not find secure port information");
+    context->retVal = ACCESS_DENIED_AMS_SERVICE_ERROR;
+    SRMSendResponse(context->retVal);
+    return OC_STACK_DELETE_TRANSACTION;
+}
+
+
+OCStackResult SendAclReq(PEContext_t *context, OCDevAddr *devAddr, OCConnectivityType connType,
+        uint16_t securedPort)
+{
+    OCStackResult ret = OC_STACK_ERROR;
+    const char GET_ACE_QUERY_FMT[] = "%s?%s=%s;%s=%s";
+    char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {};
+    uint32_t outLen = 0;
+    char uri[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {};
+    OCCallbackData cbData = {.context=NULL};
+    OCDevAddr destAddr = {.adapter = OC_ADAPTER_IP};
+    B64Result b64Ret;
+
+    VERIFY_NON_NULL(TAG, context, ERROR);
+    VERIFY_NON_NULL(TAG, devAddr, ERROR);
+
+    b64Ret = b64Encode(context->subject.id, sizeof(context->subject.id),
+                       base64Buff, sizeof(base64Buff), &outLen);
+    VERIFY_SUCCESS(TAG, B64_OK == b64Ret, ERROR);
+
+    snprintf(uri, sizeof(uri), GET_ACE_QUERY_FMT, OIC_RSRC_ACL_URI,
+                                    OIC_JSON_SUBJECT_NAME, base64Buff,
+                                    OIC_JSON_RESOURCES_NAME, context->resource);
+
+    cbData.cb = &AmsMgrAclReqCallback;
+    cbData.context = context;
+
+    destAddr = *devAddr;
+    //update port info
+    destAddr.flags = (OCTransportFlags)(destAddr.flags | OC_FLAG_SECURE);
+    destAddr.port = securedPort;
+
+    OC_LOG_V(INFO, TAG, "AMS Manager Sending Unicast ACL request with URI = %s", uri);
+    ret = OCDoResource(NULL, OC_REST_GET, uri, &destAddr, NULL,
+            connType, OC_LOW_QOS, &cbData, NULL, 0);
+
+exit:
+    OC_LOG_V(INFO, TAG, "%s returns %d ", __func__, ret);
+    return ret;
+}
+
+
+static OCStackApplicationResult AmsMgrAclReqCallback(void *ctx, OCDoHandle handle,
+    OCClientResponse * clientResponse)
+{
+    OC_LOG_V(INFO, TAG, "%s Begin", __func__ );
+
+    (void)handle;
+    PEContext_t *context = (PEContext_t *) ctx;
+    SRMAccessResponse_t rsps;
+
+    if (!ctx ||
+        !clientResponse ||
+        !clientResponse->payload||
+        (PAYLOAD_TYPE_SECURITY != clientResponse->payload->type) ||
+        (clientResponse->result != OC_STACK_OK))
+    {
+        SRMSendResponse(ACCESS_DENIED_AMS_SERVICE_ERROR);
+        goto exit;
+    }
+
+    if (context->state != AWAITING_AMS_RESPONSE)
+    {
+        OC_LOG_V(ERROR, TAG, "%s Invalid State ", __func__);
+        context->retVal = ACCESS_DENIED_AMS_SERVICE_ERROR;
+        SRMSendResponse(context->retVal);
+        return OC_STACK_DELETE_TRANSACTION;
+    }
+
+    // Verify before installing ACL if the ID of the sender of this ACL is an AMS
+    //service that this device trusts.
+    rsps = ACCESS_DENIED;
+    if((UUID_LENGTH == clientResponse->identity.id_length) &&
+        memcmp(context->amsMgrContext->amsDeviceId.id, clientResponse->identity.id,
+                       sizeof(context->amsMgrContext->amsDeviceId.id)) == 0)
+    {
+        OCStackResult ret =
+                InstallNewACL(((OCSecurityPayload*)clientResponse->payload)->securityData);
+        VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
+
+        OC_LOG_V(INFO, TAG, "%s : Calling checkPermission", __func__);
+        rsps = CheckPermission(context, &context->subject, context->resource, context->permission);
+        VERIFY_SUCCESS(TAG, (true == IsAccessGranted(rsps)), ERROR);
+
+        OC_LOG_V(INFO, TAG, "%sAccess granted, Calling SRMCallCARequestHandler", __func__);
+        context->retVal = ACCESS_GRANTED;
+        SRMSendResponse(context->retVal);
+        return OC_STACK_DELETE_TRANSACTION;
+    }
+
+exit:
+    context->retVal = ACCESS_DENIED_AMS_SERVICE_ERROR;
+    SRMSendResponse(context->retVal);
+    FreeCARequestInfo(context->amsMgrContext->requestInfo);
+    OICFree(context->amsMgrContext->endpoint);
+    return OC_STACK_DELETE_TRANSACTION;
+}
+
+
+OCStackResult UpdateAmsMgrContext(PEContext_t *context, const CAEndpoint_t *endpoint,
+                        const CARequestInfo_t *requestInfo)
+{
+    OCStackResult ret = OC_STACK_ERROR;
+
+    //The AmsMgr context endpoint and requestInfo will be free from ,
+    //AmsMgrAclReqCallback function
+    if(context->amsMgrContext->endpoint)
+    {
+        OICFree(context->amsMgrContext->endpoint);
+        context->amsMgrContext->endpoint = NULL;
+    }
+    context->amsMgrContext->endpoint = (CAEndpoint_t *)OICCalloc(1, sizeof(CAEndpoint_t ));
+    VERIFY_NON_NULL(TAG, context->amsMgrContext->endpoint, ERROR);
+    *context->amsMgrContext->endpoint = *endpoint;
+
+    if(context->amsMgrContext->requestInfo)
+    {
+        FreeCARequestInfo(context->amsMgrContext->requestInfo);
+        context->amsMgrContext->requestInfo = NULL;
+    }
+    context->amsMgrContext->requestInfo = CACloneRequestInfo(requestInfo);
+    VERIFY_NON_NULL(TAG, context->amsMgrContext->requestInfo, ERROR);
+    ret = OC_STACK_OK;
+exit:
+    return ret;
+}
+
+void FreeCARequestInfo(CARequestInfo_t *requestInfo)
+{
+    OICFree(requestInfo->info.token);
+    OICFree(requestInfo->info.options);
+    OICFree(requestInfo->info.payload);
+    OICFree(requestInfo->info.resourceUri);
+    OICFree(requestInfo);
+}
+
+
+//This method checks for Amacl resource. If Amacl is found then it fills up
+//context->amsMgrContext->amsDeviceId with amsID of the Amacl else leaves it empty.
+bool FoundAmaclForRequest(PEContext_t *context)
+{
+    OC_LOG_V(INFO, TAG, "%s:no ACL found. Searching for AMACL",__func__);
+
+    bool ret = false;
+    VERIFY_NON_NULL(TAG, context, ERROR);
+    memset(&context->amsMgrContext->amsDeviceId, 0, sizeof(context->amsMgrContext->amsDeviceId));
+
+    //Call amacl resource function to get the AMS service deviceID for the resource
+    if(OC_STACK_OK == AmaclGetAmsDeviceId(context->resource, &context->amsMgrContext->amsDeviceId))
+    {
+        OC_LOG_V(INFO, TAG, "%s:AMACL found for the requested resource %s",
+                __func__, context->resource);
+        ret = true;
+    }
+    else
+    {
+        OC_LOG_V(INFO, TAG, "%s:AMACL found for the requested resource %s",
+                __func__, context->resource);
+        ret = false;
+    }
+
+ exit:
+     return ret;
+}
+
+
+void ProcessAMSRequest(PEContext_t *context)
+{
+    OicUuid_t  emptyUuid = {.id={}};
+    OC_LOG_V(INFO, TAG, "Entering %s", __func__);
+    if(NULL != context)
+    {
+        if((false == context->matchingAclFound) && (false == context->amsProcessing))
+        {
+            context->amsProcessing = true;
+
+            //Checking if context AMS deviceId is empty
+            if(memcmp(&context->amsMgrContext->amsDeviceId, &emptyUuid, sizeof(OicUuid_t)) != 0 )
+            {
+                if(OC_STACK_OK == DiscoverAmsService(context))
+                {
+                    context->retVal = ACCESS_WAITING_FOR_AMS;
+                }
+                else
+                {
+                    context->retVal = ACCESS_DENIED_AMS_SERVICE_ERROR;
+                }
+            }
+        }
+    }
+    else
+    {
+        OC_LOG_V(INFO, TAG, "Leaving %s(context is NULL)", __func__);
+    }
+
+    if(ACCESS_WAITING_FOR_AMS == context->retVal )
+    {
+        OC_LOG_V(INFO, TAG, "Leaving %s(WAITING_FOR_AMS)", __func__);
+    }
+}
index 00fe55b..ff9a415 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "oic_malloc.h"
 #include "policyengine.h"
+#include "amsmgr.h"
 #include "resourcemanager.h"
 #include "securevirtualresourcetypes.h"
 #include "srmresourcestrings.h"
@@ -78,20 +79,19 @@ bool UuidCmp(OicUuid_t *firstId, OicUuid_t *secondId)
     return true;
 }
 
-
 /**
  * Set the state and clear other stateful context vars.
  */
 void SetPolicyEngineState(PEContext_t *context, const PEState_t state)
 {
     // Clear stateful context variables.
-    OICFree(context->subject);
-    context->subject = NULL;
-    OICFree(context->resource);
-    context->resource = NULL;
+    memset(&context->subject, 0, sizeof(context->subject));
+    memset(&context->resource, 0, sizeof(context->resource));
     context->permission = 0x0;
     context->matchingAclFound = false;
+    context->amsProcessing = false;
     context->retVal = ACCESS_DENIED_POLICY_ENGINE_ERROR;
+    memset(context->amsMgrContext, 0, sizeof(AmsMgrContext_t));
 
     // Set state.
     context->state = state;
@@ -109,12 +109,21 @@ bool IsRequestFromDevOwner(PEContext_t *context)
 
     if(OC_STACK_OK == GetDoxmDevOwnerId(&owner))
     {
-        retVal = UuidCmp(context->subject, &owner);
+        retVal = UuidCmp(&context->subject, &owner);
     }
 
     return retVal;
 }
 
+
+inline static bool IsRequestSubjectEmpty(PEContext_t *context)
+{
+    OicUuid_t emptySubject = {.id={}};
+    return (memcmp(&context->subject, &emptySubject, sizeof(OicUuid_t)) == 0) ?
+            true : false;
+}
+
+
 /**
  * Bitwise check to see if 'permission' contains 'request'.
  * @param   permission  The allowed CRUDN permission.
@@ -162,31 +171,21 @@ void CopyParamsToContext(
 {
     size_t length = 0;
 
-    // Free any existing subject.
-    OICFree(context->subject);
-    // Copy the subjectId into context.
-    context->subject = (OicUuid_t*)OICMalloc(sizeof(OicUuid_t));
-    VERIFY_NON_NULL(TAG, context->subject, ERROR);
-    memcpy(context->subject, subjectId, sizeof(OicUuid_t));
+     memcpy(&context->subject, subjectId, sizeof(OicUuid_t));
 
     // Copy the resource string into context.
     length = strlen(resource) + 1;
     if(0 < length)
     {
-        OICFree(context->resource);
-        context->resource = (char*)OICMalloc(length);
-        VERIFY_NON_NULL(TAG, context->resource, ERROR);
         strncpy(context->resource, resource, length);
         context->resource[length - 1] = '\0';
     }
 
     // Assign the permission field.
     context->permission = requestedPermission;
-
-exit:
-    return;
 }
 
+
 /**
  * Check whether 'resource' is getting accessed within the valid time period.
  * @param   acl         The ACL to check.
@@ -239,10 +238,13 @@ static bool IsAccessWithinValidTime(const OicSecAcl_t *acl)
     return false;
 }
 
+
 /**
  * Find ACLs containing context->subject.
  * Search each ACL for requested resource.
- * If resource found, check for context->permission.
+ * If resource found, check for context->permission and period validity.
+ * If the ACL is not found locally and AMACL for the resource is found
+ * then sends the request to AMS service for the ACL
  * Set context->retVal to result from first ACL found which contains
  * correct subject AND resource.
  *
@@ -258,22 +260,25 @@ void ProcessAccessRequest(PEContext_t *context)
 
         // Start out assuming subject not found.
         context->retVal = ACCESS_DENIED_SUBJECT_NOT_FOUND;
+
+        // Loop through all ACLs with a matching Subject searching for the right
+        // ACL for this request.
         do
         {
-            OC_LOG(INFO, TAG, "ProcessAccessRequest(): getting ACL...");
-            currentAcl = GetACLResourceData(context->subject, &savePtr);
+            OC_LOG_V(INFO, TAG, ("%s: getting ACL..."),__func__);
+            currentAcl = GetACLResourceData(&context->subject, &savePtr);
+
             if(NULL != currentAcl)
             {
                 // Found the subject, so how about resource?
-                OC_LOG(INFO, TAG, "ProcessAccessRequest(): \
-                    found ACL matching subject.");
+                OC_LOG_V(INFO, TAG, ("%s:found ACL matching subject"),__func__);
+
+                // Subject was found, so err changes to Rsrc not found for now.
                 context->retVal = ACCESS_DENIED_RESOURCE_NOT_FOUND;
-                OC_LOG(INFO, TAG, "ProcessAccessRequest(): \
-                    Searching for resource...");
+                OC_LOG_V(INFO, TAG, ("%s:Searching for resource..."),__func__);
                 if(IsResourceInAcl(context->resource, currentAcl))
                 {
-                    OC_LOG(INFO, TAG, "ProcessAccessRequest(): \
-                        found matching resource in ACL.");
+                    OC_LOG_V(INFO, TAG, ("%s:found matching resource in ACL"),__func__);
                     context->matchingAclFound = true;
 
                     // Found the resource, so it's down to valid period & permission.
@@ -281,8 +286,7 @@ void ProcessAccessRequest(PEContext_t *context)
                     if(IsAccessWithinValidTime(currentAcl))
                     {
                         context->retVal = ACCESS_DENIED_INSUFFICIENT_PERMISSION;
-                        if(IsPermissionAllowingRequest(currentAcl->permission, \
-                        context->permission))
+                        if(IsPermissionAllowingRequest(currentAcl->permission, context->permission))
                         {
                             context->retVal = ACCESS_GRANTED;
                         }
@@ -291,29 +295,24 @@ void ProcessAccessRequest(PEContext_t *context)
             }
             else
             {
-                OC_LOG(INFO, TAG, "ProcessAccessRequest(): \
-                    no ACL found matching subject .");
+                OC_LOG_V(INFO, TAG, ("%s:no ACL found matching subject for resource %s"),__func__, context->resource);
             }
         }
         while((NULL != currentAcl) && (false == context->matchingAclFound));
 
         if(IsAccessGranted(context->retVal))
         {
-            OC_LOG(INFO, TAG, "ProcessAccessRequest(): \
-                Leaving ProcessAccessRequest(ACCESS_GRANTED)");
+            OC_LOG_V(INFO, TAG, ("%s:Leaving ProcessAccessRequest(ACCESS_GRANTED)"), __func__);
         }
         else
         {
-            OC_LOG(INFO, TAG, "ProcessAccessRequest(): \
-                Leaving ProcessAccessRequest(ACCESS_DENIED)");
+            OC_LOG_V(INFO, TAG, ("%s:Leaving ProcessAccessRequest(ACCESS_DENIED)"), __func__);
         }
     }
     else
     {
-        OC_LOG(INFO, TAG, "ProcessAccessRequest(): \
-            Leaving ProcessAccessRequest(context is NULL)");
+        OC_LOG_V(INFO, TAG, ("%s:Leaving ProcessAccessRequest(context is NULL)"), __func__);
     }
-
 }
 
 /**
@@ -338,12 +337,16 @@ SRMAccessResponse_t CheckPermission(
     VERIFY_NON_NULL(TAG, resource, ERROR);
 
     // Each state machine context can only be processing one request at a time.
-    // Therefore if the context is not in AWAITING_REQUEST state, return error.
-    // Otherwise, change to BUSY state and begin processing request.
-    if(AWAITING_REQUEST == context->state)
+    // Therefore if the context is not in AWAITING_REQUEST or AWAITING_AMS_RESPONSE
+    // state, return error. Otherwise, change to BUSY state and begin processing request.
+    if(AWAITING_REQUEST == context->state || AWAITING_AMS_RESPONSE == context->state)
     {
-        SetPolicyEngineState(context, BUSY);
-        CopyParamsToContext(context, subjectId, resource, requestedPermission);
+        if(AWAITING_REQUEST == context->state)
+        {
+            SetPolicyEngineState(context, BUSY);
+            CopyParamsToContext(context, subjectId, resource, requestedPermission);
+        }
+
         // Before doing any processing, check if request coming
         // from DevOwner and if so, always GRANT.
         if(IsRequestFromDevOwner(context))
@@ -352,19 +355,46 @@ SRMAccessResponse_t CheckPermission(
         }
         else
         {
+            OicUuid_t saveSubject = {.id={}};
+            bool isSubEmpty = IsRequestSubjectEmpty(context);
+
             ProcessAccessRequest(context);
+
             // If matching ACL not found, and subject != wildcard, try wildcard.
             if((false == context->matchingAclFound) && \
-                (false == IsWildCardSubject(context->subject)))
+              (false == IsWildCardSubject(&context->subject)))
             {
-                OICFree(context->subject);
-                context->subject = (OicUuid_t*)OICMalloc(sizeof(OicUuid_t));
-                VERIFY_NON_NULL(TAG, context->subject, ERROR);
-                memcpy(context->subject, &WILDCARD_SUBJECT_ID,
-                    sizeof(OicUuid_t));
+                //Saving subject for Amacl check
+                memcpy(&saveSubject, &context->subject,sizeof(OicUuid_t));
+
+                //Setting context subject to WILDCARD_SUBJECT_ID
+                //TODO: change ProcessAccessRequest method signature to
+                //ProcessAccessRequest(context, subject) so that context
+                //subject is not tempered.
+                memset(&context->subject, 0, sizeof(context->subject));
+                memcpy(&context->subject, &WILDCARD_SUBJECT_ID,sizeof(OicUuid_t));
                 ProcessAccessRequest(context); // TODO anonymous subj can result
                                                // in confusing err code return.
             }
+
+            //No local ACE found for the request so checking Amacl resource
+            if(ACCESS_GRANTED != context->retVal)
+            {
+                //If subject is not empty then restore the original subject
+                //else keep the subject to WILDCARD_SUBJECT_ID
+                if(!isSubEmpty)
+                {
+                    memcpy(&context->subject, &saveSubject, sizeof(OicUuid_t));
+                }
+
+                //FoundAmaclForRequest method checks for Amacl and fills up
+                //context->amsMgrContext->amsDeviceId with the AMS deviceId
+                //if Amacl was found for the requested resource.
+                if(FoundAmaclForRequest(context))
+                {
+                    ProcessAMSRequest(context);
+                }
+            }
         }
     }
     else
@@ -374,7 +404,19 @@ SRMAccessResponse_t CheckPermission(
 
     // Capture retVal before resetting state for next request.
     retVal = context->retVal;
-    SetPolicyEngineState(context, AWAITING_REQUEST);
+
+    //Change the state of PE to "AWAITING_AMS_RESPONSE", if waiting
+    //for response from AMS service else to "AWAITING_REQUEST"
+    if(ACCESS_WAITING_FOR_AMS == retVal)
+    {
+        OC_LOG(INFO, TAG, ("Setting PE State to AWAITING_AMS_RESPONSE"));
+        context->state = AWAITING_AMS_RESPONSE;
+    }
+    else if(!context->amsProcessing)
+    {
+        OC_LOG(INFO, TAG, ("Resetting PE context and PE State to AWAITING_REQUEST"));
+        SetPolicyEngineState(context, AWAITING_REQUEST);
+    }
 
 exit:
     return retVal;
@@ -387,6 +429,7 @@ exit:
  */
 OCStackResult InitPolicyEngine(PEContext_t *context)
 {
+    context->amsMgrContext = (AmsMgrContext_t *)OICMalloc(sizeof(AmsMgrContext_t));
     if(NULL != context)
     {
         SetPolicyEngineState(context, AWAITING_REQUEST);
@@ -407,6 +450,6 @@ void DeInitPolicyEngine(PEContext_t *context)
     {
         SetPolicyEngineState(context, STOPPED);
     }
-
+    OICFree(context->amsMgrContext);
     return;
 }
index 2a7e395..25602c3 100644 (file)
 #include "ocstack.h"
 #include "logger.h"
 #include "cainterface.h"
-#include "secureresourcemanager.h"
 #include "resourcemanager.h"
 #include "credresource.h"
 #include "policyengine.h"
+#include "srmutility.h"
+#include "amsmgr.h"
 #include "oic_string.h"
+#include "oic_malloc.h"
+#include "securevirtualresourcetypes.h"
+#include "secureresourcemanager.h"
 #include <string.h>
 
 #define TAG  "SRM"
@@ -55,6 +59,55 @@ void SRMRegisterProvisioningResponseHandler(SPResponseCallback respHandler)
 {
     gSPResponseHandler = respHandler;
 }
+
+
+static void SRMSendUnAuthorizedAccessresponse(PEContext_t *context)
+{
+    CAResponseInfo_t responseInfo = {.result = CA_EMPTY};
+    memcpy(&responseInfo.info, &(context->amsMgrContext->requestInfo->info),
+            sizeof(responseInfo.info));
+    responseInfo.info.payload = NULL;
+    responseInfo.result = CA_UNAUTHORIZED_REQ;
+    if (CA_STATUS_OK != CASendResponse(context->amsMgrContext->endpoint, &responseInfo))
+    {
+        OC_LOG(ERROR, TAG, "Failed in sending response to a unauthorized request!");
+    }
+    else
+    {
+        OC_LOG(INFO, TAG, "Succeed in sending response to a unauthorized request!");
+    }
+}
+
+
+void SRMSendResponse(SRMAccessResponse_t responseVal)
+{
+    OC_LOG(INFO, TAG, "Sending response to remote device");
+
+    if (IsAccessGranted(responseVal) && gRequestHandler)
+    {
+        OC_LOG_V(INFO, TAG, "%s : Access granted. Passing Request to RI layer", __func__);
+        if (!g_policyEngineContext.amsMgrContext->endpoint ||
+                !g_policyEngineContext.amsMgrContext->requestInfo)
+        {
+            OC_LOG_V(ERROR, TAG, "%s : Invalid arguments", __func__);
+            SRMSendUnAuthorizedAccessresponse(&g_policyEngineContext);
+            goto exit;
+        }
+        gRequestHandler(g_policyEngineContext.amsMgrContext->endpoint,
+                g_policyEngineContext.amsMgrContext->requestInfo);
+    }
+    else
+    {
+        OC_LOG_V(INFO, TAG, "%s : ACCESS_DENIED.", __func__);
+        SRMSendUnAuthorizedAccessresponse(&g_policyEngineContext);
+    }
+
+exit:
+    //Resting PE state to AWAITING_REQUEST
+    SetPolicyEngineState(&g_policyEngineContext, AWAITING_REQUEST);
+}
+
+
 /**
  * @brief   Handle the request from the SRM.
  * @param   endPoint       [IN] Endpoint object from which the response is received.
@@ -80,42 +133,55 @@ void SRMRequestHandler(const CAEndpoint_t *endPoint, const CARequestInfo_t *requ
     int position = 0;
     if (uri)
     {
+        //Skip query and pass the resource uri
         position = uri - requestInfo->info.resourceUri;
     }
-    if (position > MAX_URI_LENGTH)
+    else
+    {
+        position = strlen(requestInfo->info.resourceUri);
+    }
+    if (MAX_URI_LENGTH < position  || 0 > position)
     {
-        OC_LOG(ERROR, TAG, "URI length is too long");
+        OC_LOG(ERROR, TAG, "Incorrect URI length");
         return;
     }
     SRMAccessResponse_t response = ACCESS_DENIED;
-    if (position > 0)
+    char newUri[MAX_URI_LENGTH + 1];
+    OICStrcpyPartial(newUri, MAX_URI_LENGTH + 1, requestInfo->info.resourceUri, position);
+
+    //New request are only processed if the policy engine state is AWAITING_REQUEST.
+    if(AWAITING_REQUEST == g_policyEngineContext.state)
     {
-        char newUri[MAX_URI_LENGTH + 1];
-        OICStrcpyPartial(newUri, MAX_URI_LENGTH + 1, requestInfo->info.resourceUri, position);
-        //Skip query and pass the newUri.
-        response = CheckPermission(&g_policyEngineContext, &subjectId,
-                              newUri,
-                              GetPermissionFromCAMethod_t(requestInfo->method));
+        OC_LOG_V(INFO, TAG, "Processing request with uri, %s for method, %d",
+                requestInfo->info.resourceUri, requestInfo->method);
+        response = CheckPermission(&g_policyEngineContext, &subjectId, newUri,
+                GetPermissionFromCAMethod_t(requestInfo->method));
     }
     else
     {
-        //Pass resourceUri if there is no query info.
-        response = CheckPermission(&g_policyEngineContext, &subjectId,
-                              requestInfo->info.resourceUri,
-                              GetPermissionFromCAMethod_t(requestInfo->method));
+        OC_LOG_V(INFO, TAG, "PE state %d. Ignoring request with uri, %s for method, %d",
+                g_policyEngineContext.state, requestInfo->info.resourceUri, requestInfo->method);
     }
+
     if (IsAccessGranted(response) && gRequestHandler)
     {
         return (gRequestHandler(endPoint, requestInfo));
     }
 
-    // Form a 'access deny' or 'Error' response and send to peer
+    // Form a 'Error', 'slow response' or 'access deny' response and send to peer
     CAResponseInfo_t responseInfo = {.result = CA_EMPTY};
     memcpy(&responseInfo.info, &(requestInfo->info), sizeof(responseInfo.info));
     responseInfo.info.payload = NULL;
-    if (!gRequestHandler)
+
+    VERIFY_NON_NULL(TAG, gRequestHandler, ERROR);
+
+    if(ACCESS_WAITING_FOR_AMS == response)
     {
-        responseInfo.result = CA_INTERNAL_SERVER_ERROR;
+        OC_LOG(INFO, TAG, "Sending slow response");
+
+        UpdateAmsMgrContext(&g_policyEngineContext, endPoint, requestInfo);
+        responseInfo.result = CA_EMPTY;
+        responseInfo.info.type = CA_MSG_ACKNOWLEDGE;
     }
     else
     {
@@ -124,6 +190,7 @@ void SRMRequestHandler(const CAEndpoint_t *endPoint, const CARequestInfo_t *requ
          * CA_UNAUTHORIZED_REQ or CA_FORBIDDEN_REQ depending
          * upon SRMAccessResponseReasonCode_t
          */
+        OC_LOG(INFO, TAG, "Sending for regular response");
         responseInfo.result = CA_UNAUTHORIZED_REQ;
     }
 
@@ -131,6 +198,13 @@ void SRMRequestHandler(const CAEndpoint_t *endPoint, const CARequestInfo_t *requ
     {
         OC_LOG(ERROR, TAG, "Failed in sending response to a unauthorized request!");
     }
+    return;
+exit:
+    responseInfo.result = CA_INTERNAL_SERVER_ERROR;
+    if (CA_STATUS_OK != CASendResponse(endPoint, &responseInfo))
+    {
+        OC_LOG(ERROR, TAG, "Failed in sending response to a unauthorized request!");
+    }
 }
 
 /**
@@ -169,7 +243,8 @@ void SRMResponseHandler(const CAEndpoint_t *endPoint, const CAResponseInfo_t *re
  */
 void SRMErrorHandler(const CAEndpoint_t *endPoint, const CAErrorInfo_t *errorInfo)
 {
-    OC_LOG(INFO, TAG, "Received error from remote device");
+    OC_LOG_V(INFO, TAG, "Received error from remote device with result, %d for request uri, %s",
+            errorInfo->result, errorInfo->info.resourceUri);
     if (gErrorHandler)
     {
         gErrorHandler(endPoint, errorInfo);
index 8ad43a8..6890530 100644 (file)
@@ -102,8 +102,6 @@ TEST(PolicyEngineCore, DeInitPolicyEngine)
 {
     DeInitPolicyEngine(&g_peContext);
     EXPECT_EQ(STOPPED, g_peContext.state);
-    EXPECT_EQ(NULL, g_peContext.subject);
-    EXPECT_EQ(NULL, g_peContext.resource);
     EXPECT_EQ((uint16_t)0, g_peContext.permission);
     EXPECT_FALSE(g_peContext.matchingAclFound);
     EXPECT_EQ(ACCESS_DENIED_POLICY_ENGINE_ERROR, g_peContext.retVal);
diff --git a/resource/csdk/stack/samples/linux/secure/README b/resource/csdk/stack/samples/linux/secure/README
new file mode 100644 (file)
index 0000000..e874653
--- /dev/null
@@ -0,0 +1,14 @@
+Testing AMS service:
+1. Copy subjectID ("NDQ0NDMzMzMyMjIyMTExMQ==") of ACE with resource "/a/led" from AMS service 
+   database file, "oic_amss_db.json" into client Doxm resource deviceID located in file 
+   "oic_svr_client.json".
+2. Start ocserverbasicops
+3. start ocamsservice
+4. Start occlientbasicops
+
+
+Expected Result:
+1. New ACE with subjectID="NDQ0NDMzMzMyMjIyMTExMQ==" and rsrc="/a/led/" will be appended to the
+   server ACL resource in file "oic_svr_db_server.json".
+2. GET request made by occlientbasicops will be received successfully
+3. PUT reuest will received with result "OC_STACK_UNAUTHORIZED_REQ"
index 038c998..db10b49 100644 (file)
@@ -66,8 +66,9 @@ samples_env.AppendUnique(CPPDEFINES = ['TB_LOG'])
 
 ocserverbasicops = samples_env.Program('ocserverbasicops', ['common.cpp', 'ocserverbasicops.cpp'])
 occlientbasicops = samples_env.Program('occlientbasicops', ['common.cpp', 'occlientbasicops.cpp'])
+ocamsservice = samples_env.Program('ocamsservice', ['common.cpp', 'ocamsservice.cpp'])
 
-Alias("samples", [ocserverbasicops, occlientbasicops])
+Alias("samples", [ocserverbasicops, occlientbasicops, ocamsservice])
 
 env.AppendTarget('samples')
 
@@ -79,4 +80,6 @@ samples_env.Alias("install", samples_env.Install( sec_samples_build_dir,
     sec_samples_src_dir + 'oic_svr_db_server.json'))
 samples_env.Alias("install", samples_env.Install( sec_samples_build_dir,
     sec_samples_src_dir + 'oic_svr_db_client.json'))
+samples_env.Alias("install", samples_env.Install( sec_samples_build_dir,
+    sec_samples_src_dir + 'oic_amss_db.json'))
 
diff --git a/resource/csdk/stack/samples/linux/secure/ocamsservice.cpp b/resource/csdk/stack/samples/linux/secure/ocamsservice.cpp
new file mode 100644 (file)
index 0000000..c22d371
--- /dev/null
@@ -0,0 +1,76 @@
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <pthread.h>
+#include "ocstack.h"
+#include "logger.h"
+#include "common.h"
+
+#define TAG  PCF("SRM-AMSS")
+
+int gQuitFlag = 0;
+
+//AMS service database, hold AMS service Identity and
+//the PSK credentials of trusted devices
+static char AMSS_DB_FILE[] = "oic_amss_db.json";
+
+/* SIGINT handler: set gQuitFlag to 1 for graceful termination */
+void handleSigInt(int signum)
+{
+    if (signum == SIGINT)
+    {
+        gQuitFlag = 1;
+    }
+}
+
+FILE* service_fopen(const char *path, const char *mode)
+{
+    (void)path;
+    return fopen(AMSS_DB_FILE, mode);
+}
+
+int main(int /*argc*/, char* /*argv*/[])
+{
+    struct timespec timeout;
+
+    OC_LOG(DEBUG, TAG, "OCAMS service is starting...");
+
+    // Initialize Persistent Storage for SVR database
+    OCPersistentStorage ps = { service_fopen, fread, fwrite, fclose, unlink };
+    OCRegisterPersistentStorageHandler(&ps);
+
+    if (OCInit(NULL, 0, OC_SERVER) != OC_STACK_OK)
+    {
+        OC_LOG(ERROR, TAG, "OCStack init error");
+        return 0;
+    }
+
+    timeout.tv_sec  = 0;
+    timeout.tv_nsec = 100000000L;
+
+    // Break from loop with Ctrl-C
+    OC_LOG(INFO, TAG, "Entering ocamsservice main loop...");
+    signal(SIGINT, handleSigInt);
+    while (!gQuitFlag)
+    {
+        if (OCProcess() != OC_STACK_OK)
+        {
+            OC_LOG(ERROR, TAG, "OCStack process error");
+            return 0;
+        }
+        nanosleep(&timeout, NULL);
+    }
+
+    OC_LOG(INFO, TAG, "Exiting ocamsservice main loop...");
+
+    if (OCStop() != OC_STACK_OK)
+    {
+        OC_LOG(ERROR, TAG, "OCStack process error");
+    }
+
+    return 0;
+}
diff --git a/resource/csdk/stack/samples/linux/secure/oic_amss_db.json b/resource/csdk/stack/samples/linux/secure/oic_amss_db.json
new file mode 100644 (file)
index 0000000..9543a87
--- /dev/null
@@ -0,0 +1,64 @@
+{
+    "acl": [
+        {
+            "sub": "Kg==",
+            "rsrc": [
+                "/oic/res",
+                "/oic/d",
+                "/oic/p",
+                "/oic/res/types/d",
+                "/oic/ad",
+                "/oic/sec/acl",
+                "/oic/sec/amacl"
+                       ],
+                       "perms": 2,
+                       "ownrs" : ["MTExMTExMTExMTExMTExMQ=="]
+               },
+        {
+            "sub": "Kg==",
+            "rsrc": [
+                "/oic/sec/doxm",
+                "/oic/sec/pstat"
+             ],
+             "perms": 2,
+             "ownrs" : ["MTExMTExMTExMTExMTExMQ=="]
+        },
+        {
+            "sub": "MjIyMjIyMjIyMjIyMjIyMg==",
+            "rsrc": ["/oic/sec/acl",
+                      "/oic/sec/cred"],
+            "perms": 8,
+            "ownrs" : ["MjIyMjIyMjIyMjIyMjIyMg=="]
+        },
+        {
+            "sub": "NDQ0NDMzMzMyMjIyMTExMQ==",
+            "rsrc": ["/a/led"],
+            "perms": 6,
+            "ownrs" : ["MjIyMjIyMjIyMjIyMjIyMg=="]
+        }
+       ],
+       "pstat":        {
+               "isop": true,
+               "deviceid":     "ZGV2aWNlaWQAAAAAABhanw==",
+               "ch": 0,
+               "cm":   0,
+               "tm":   0,
+               "om":   3,
+               "sm":   [3]
+       },
+       "doxm": {
+               "oxm":  [0],
+               "oxmsel": 0,
+               "sct": 1,
+               "owned": true,
+               "deviceid":     "MTkxOTE5MTkxOTE5MTkxOQ==",
+               "ownr": "YWRtaW5EZXZpY2VVVUlEAA=="
+       },
+       "cred": [{
+               "credid": 1,
+               "sub": "MTExMTExMTExMTExMTExMQ==",
+               "credtyp": 1,
+               "pvdata": "QkJCQkJCQkJCQkJCQkJCQg==",
+        "ownrs" : ["MjIyMjIyMjIyMjIyMjIyMg=="]
+       }]
+}
index 4211ee3..9456b41 100644 (file)
             "ownrs" : ["MjIyMjIyMjIyMjIyMjIyMg=="]
         }
        ],
+       "amacl": [{
+               "rsrc" : ["/a/led"],
+               "amss" : ["MTkxOTE5MTkxOTE5MTkxOQ=="],
+               "ownrs" : ["MjIyMjIyMjIyMjIyMjIyMg=="]
+       }],
        "pstat":        {
                "isop": true,
                "deviceid":     "ZGV2aWNlaWQAAAAAABhanw==",
            "credtyp": 1,
            "pvdata": "QUFBQUFBQUFBQUFBQUFBQQ==",
         "ownrs" : ["MjIyMjIyMjIyMjIyMjIyMg=="]
+       },
+       {
+           "credid": 4,
+           "sub": "NDQ0NDMzMzMyMjIyMTExMQ==",
+           "credtyp": 1,
+           "pvdata": "QUFBQUFBQUFBQUFBQUFBQQ==",
+        "ownrs" : ["MjIyMjIyMjIyMjIyMjIyMg=="]
+       },
+       {
+           "credid": 5,
+           "sub": "MTkxOTE5MTkxOTE5MTkxOQ==",
+           "credtyp": 1,
+           "pvdata": "QkJCQkJCQkJCQkJCQkJCQg==",
+        "ownrs" : ["MjIyMjIyMjIyMjIyMjIyMg=="]
        }]
 }
index 6f905ef..84bb385 100644 (file)
@@ -49,7 +49,7 @@ if target_os not in ['windows', 'winrt']:
        # Note: 'pthread' is in libc for android. On other platform, if use
        # new gcc(>4.9?) it isn't required, otherwise, it's required
        if target_os != 'android':
-               examples_env.AppendUnique(LIBS = ['-lpthread'])
+               examples_env.AppendUnique(LIBS = ['-lpthread', '-ldl'])
 
 examples_env.AppendUnique(LIBPATH = [env.get('BUILD_DIR')])
 examples_env.AppendUnique(RPATH = [env.get('BUILD_DIR')])
index 458a2ab..06a14bf 100644 (file)
@@ -47,7 +47,7 @@ provisiontests_env.PrependUnique(CPPPATH = [
                ])
 
 provisiontests_env.AppendUnique(CXXFLAGS = ['-std=c++0x', '-Wall', '-pthread'])
-provisiontests_env.AppendUnique(LIBS = ['-lpthread'])
+provisiontests_env.AppendUnique(LIBS = ['-lpthread', '-ldl'])
 provisiontests_env.AppendUnique(LIBPATH = [env.get('BUILD_DIR')])
 provisiontests_env.AppendUnique(LIBPATH = [src_dir + '/extlibs/gtest/gtest-1.7.0/lib/.libs'])
 provisiontests_env.PrependUnique(LIBS = [