Thunder Security provides a way to control access to various RDK Services on the STBs for web and native apps. This requires apps to provide a security token as part of each request to a RDK Service.

This token is generated automatically by the WPE runtime for web apps. The security token contains details on the application context like app URL. Based on the access permissions configured, Thunder will check the security token as part of each incoming request and allow/deny access to the RDK service. More details are explained below.

Figure 1:  Component diagram.

Figure 2.  Sequence Diagram

Notes:  The Spark or WPE runtime loads the application.  The application that wants to use Thunder services creates the ThunderClient.  When the client is created, it requests a security token from the runtime.  The runtime then requests the token directly from the security agent through COM/RPC using the application context (the application's URL).  The security agent then creates and returns the token and returns it to the client.  As noted, the token is not returned back to the application that creates the Thunder client.  Once the application has created the Thunder Client, it then can invoke a service on a plugin... in this case Plugin1.foo().  The Thunder Client creates the request to Thunder by including the security token.  The Thunder Framework (not the actual plugin) checks with the security plugin to determine if the application can access this plugin based on the permissions file, and if so, allows the plugin to perform the request with the result being returned to the application.

Sending Security Token in JSON-RPC Requests

Web Apps

Web Apps that use ThunderJS to access plugins don't have to do anything to pass the security token. This is handled by the WPE runtime and ThunderJS. WPE runtime will get details of the web app (URL) and send these details to WPEFramework process to get a security token. ThunderJS client will read this token and include it as part of each request.

Native Apps

a) Native apps can use the GetSecurityToken() API from libWPEFrameworkSecurityUtil.so to get the security token.

#include <securityagent/SecurityTokenUtil.h>
#define MAX_LENGTH 1024
 
 
unsigned char buffer[MAX_LENGTH] = {0};
int ret = GetSecurityToken(MAX_LENGTH,buffer);
if(ret > 0)
{
    string sToken = (char*)buffer;
    string query = "token=" + sToken;
    auto thunderClient = WPEFramework::JSONRPC::LinkType<WPEFramework::Core::JSON::IElement>("org.rdk.DisplaySettings", "", false, query);
}


b) Native apps can use the WPEFrameworkSecurityUtility application to get a security token for localhost. This will give a security token as part of a json response as shown below.

cd /opt/logs# /usr/bin/WPEFrameworkSecurityUtility
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cmwiOiJodHRwOi8vbG9jYWxob3N0In0.u1b-drnYqxLlxAHqTLEFu8PmJ2iKNvrnvmyO0ofvrOI","success":true}

Native apps will have to send this token as a query string to JSONRPC::LinkType object as shown below.

// assuming sToken contains the token retreived from WPEFrameworkSecurityUtility
string sToken;
 
string query = "token=" + sToken;
auto thunderClient = WPEFramework::JSONRPC::LinkType<WPEFramework::Core::JSON::IElement>("org.rdk.DisplaySettings", "", false, query);

Sending Security Token in HTTP Requests

Security Token can be passed in the header as part of REST API calls to thunder to access RDK Services. These HTTP calls are used during development, triage and testing.

Similar to native apps, we can run the WPEFrameworkSecurityUtility application to get a security token for localhost. This will give a security token as part of the json response which should be passed as part of Authorization header as shown below.

cd /opt/logs# /usr/bin/WPEFrameworkSecurityUtility
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cmwiOiJodHRwOi8vbG9jYWxob3N0In0.u1b-drnYqxLlxAHqTLEFu8PmJ2iKNvrnvmyO0ofvrOI","success":true}
 
 
cd /opt/logs# curl -H "Content-Type: application/json"  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cmwiOiJodHRwOi8vbG9jYWxob3N0In0.u1b-drnYqxLlxAHqTLEFu8PmJ2iKNvrnvmyO0ofvrOI" -X POST   -d '{"jsonrpc":"2.0","id":1,"method":"org.rdk.DisplaySettings.1.getCurrentResolution"}' http://127.0.0.1:9998/jsonrpc
 
{"jsonrpc":"2.0","id":1,"result":{"resolution":"1080p60","success":true}}

Additional Info on Security Token

The security token generated on a device is only valid for that device. It cannot be used for another device. Also, the token needs to be regenerated if the device is rebooted or services are restarted.

Error Handling

If no security token is passed in the request or invalid security token is passed, then WPEFramework::Core::ERROR_PRIVILIGED_REQUEST (24) error code is returned.

Native Apps

Any calls to WPEFramework::JSONRPC::LinkType APIs will return WPEFramework::Core::ERROR_PRIVILIGED_REQUEST if correct security token is not passed.

// Error code when no security token is passed.
 
auto thunderClient = WPEFramework::JSONRPC::LinkType<WPEFramework::Core::JSON::IElement>("org.rdk.DisplaySettings", "");
JsonObject joParams;
JsonObject joResult;
uint32_t status = thunderClient.Invoke(2000, "getCurrentResolution", joParams, joResult);
 
 
if(status == WPEFramework::Core::ERROR_PRIVILIGED_REQUEST)
{
    cout << "Access denied. Pass valid security token" << endl;
}

Http Requests

cd /opt/logs# curl -H "Content-Type: application/json"   -X POST   -d '{"jsonrpc":"2.0","id":1,"method":"Controller.1.status@org.rdk.DisplaySettings"}' http://127.0.0.1:9998/jsonrpc
 
{"jsonrpc":"2.0","id":1,"error":{"code":24,"message":"Request needs authorization. Missing or invalid token."}}

RFC Support

Thunder Security can be enabled/disabled using RFC Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.ThunderSecurity.Enable. When Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.ThunderSecurity.Enable is set to true, then Thunder Security is enabled and disabled when set to false. 

The RFC can be set using XCONF or locally on the STB using tr181 commands. STB needs to be rebooted after changing the RFC value.

Details on Security Permissions

The Thunder security permissions or ACL are defined under /etc/thunder_acl.json. Sample permissions are shown below as an example. "assign" contains a list of urls for which different roles are assigned. 

"roles" define each of the roles which specify the ACL permissions or rules for plugins to either "blocked" or "allowed". if there is a "default" rule set (to "allowed" or "blocked"), then subsequent rules listed under that role are exceptions to the default rule. For instance the comcast role in the sample acl below has blocked access to all plugins except Messenger.

There is also support to control access to specific APIs in a particular plugin. For development and testing purposes /etc/thunder_acl.json file can be copied to /opt/thunder_acl.json and edited. This is allowed only on VBN builds.

{
  "assign": [
    {
      "url": "*://localhost",
      "role": "local"
    },
    {
      "url": "*://localhost:*",
      "role": "local"
    },
    {
      "url": "*://127.0.0.1",
      "role": "local"
    },
    {
      "url": "*://127.0.0.1:*",
      "role": "local"
    },
    {
      "url": "*://[::1]",
      "role": "local"
    },
    {
      "url": "*://[::1]:*",
      "role": "local"
    },
    {
      "url": "*://[0:0:0:0:0:0:0:1]",
      "role": "local"
    },
    {
      "url": "*://[0:0:0:0:0:0:0:1]:*",
      "role": "local"
    },
    {
      "url": "file://*",
      "role": "local"
    },
    {
      "url": "*://*.comcast.com",
      "role": "comcast"
    },
    {
      "url": "*://metrological.com",
      "role": "metrological"
    },
    {
      "url": "*",
      "role": "default"
    }
  ],
  "roles": {
    "default" : {
      "default" : "blocked"
    },
    "local" : {
      "default" : "allowed"
    },
    "metrological": {
      "default": "blocked",
      "DeviceInfo": {
        "default": "allowed",
        "methods": [ "register", "unregister" ]
      },
      "JSONRPCPlugin": {
        "default": "blocked",
        "methods": [ "time", "status" ]
      }
    },
    "comcast": {
      "default": "blocked",
      "Messenger": {
        "default": "allowed"
      }
    }
  }
}