octoblu / meshblu

Meshblu is a cross-protocol IoT machine-to-machine messaging system.
https://meshblu.readme.io/
MIT License
815 stars 182 forks source link

Use-case for production #115

Closed drasko closed 8 years ago

drasko commented 8 years ago

I am wondering about production scenarios with Meshblu. Let's take this use-case:

Is this how it is supposed to work?

I see several problems with this scenario:

How do we handle these issues and what is a correct procedure for this use-case - i.e. for making a connected product with Meshblu?

chrismatthieu commented 8 years ago

Great question and one that we have discussed several times. There are a few ways to address this scenario:

  1. Your application could manage the controls of which properties the new lamp owner could modify.
  2. You could transition away from owner (like we are doing) and manage all devices purely with whitelists and blacklists. This would allow you to give the new "owner" discover, send, and receive permissions but not configure.
  3. We have implemented a concept of virtual devices (not yet documented). This approach allows you to create a UUID for a virtual device that a user or groups of users can "own" that simply points to the actual device. This approach may give you more flexibility to managing and securing the actual device. We can elaborate more on this approach if it sounds interesting to you...
drasko commented 8 years ago

@chrismatthieu this is indeed very important question, as without this explained I do not see how Meshblu can be used as a cloud platform for a developer/producer to put his product on the market.

1. Your application could manage the controls of which properties the new lamp owner could modify.

I do not like really much this approach, because then every application would have to manage presentation to the user.

However - this would not prevent user to modify the Device representation in the database. As he receives his UUID/auth_token when he registers on Meshblu he can just make the curl calls over /devices route (when he claimed the device he became the owner), independently of the app you provided.

2. You could transition away from owner (like we are doing) and manage all devices purely with whitelists and blacklists. This would allow you to give the new "owner" discover, send, and receive permissions but not configure.

This looks like the best solution to me and this is what I had in mind:

However, I still see two problems with this approach:

  1. When user is whitelisted to discover, he can see ALL device content. There is no "scope" limit. Some fields should be potentially kept private for the producer (real owner of the device) - like a password to enter service mode of the device, or some device statistics...
  2. User can not "share" his device with other users. For example, he can not share a control over lamp or door lock with his family members... This is because user is just "whitelisted", and not real owner, plus he is not whitelisted in the "config" - so he can not modify the device to add other users to the whitelist! Only owner or someone whitelisted in the "config" can do this - and you will not call Google to add access to your router to your wife.

I am thinking about these potential solutions:

This could potentially resolve both problems I mentioned. Do you see some problems in this thinking?

3. We have implemented a concept of virtual devices (not yet documented). This approach allows you to create a UUID for a virtual device that a user or groups of users can "own" that simply points to the actual device. This approach may give you more flexibility to managing and securing the actual device. We can elaborate more on this approach if it sounds interesting to you...

Yes, this sound interesting, but I still can not see the real value in this (lack of info). On the contrary, I am very afraid that this will potentially complicate the system. Imagine that practically all devices you have to duplicate with Virtual Device(s) - and in IoT we expect already millions and millions of devices... I suppose that this Virtual Device will have a separate auth_token - which is an additional thing to sell to developer, and it doubles the cost of the product (cloud wise).

But yes, please do tell me more about the concept - I can not completely understand it without further explications.

chrismatthieu commented 8 years ago

While I agree with you about virtual devices adding more complexity to your app, I believe that this option (#3) will meet your needs. I'll defer to someone else on the team that can explain virtual devices and how they can be used as groups better than me.

iamruinous commented 8 years ago

We've discussed virtual devices a lot amongst the team and implemented some prototypes. I'll write up something to explain it in detail.

drasko commented 8 years ago

@iamruinous thanks a lot. I think this thread is a good place to post a summary, I am very interested about the concept.

Can you please also comment on my idea of adding the user and scope fields to Device model?

iamruinous commented 8 years ago

Currently owner imbues special access to the device placed in there, bypassing the whitelists. I'd like to see that removed. Whitelists should be the only thing that determine authorization. Owner should simply be metadata and have no special meaning.

Adding user and scope would lead to more special cases. The whitelists should provide the necessary mechanisms to build robust applications. If it can't be done with the current set (configure, discover, receive, send, configureAs, discoverAs, receiveAs, sendAs) then we should add more whitelists.

The more complicated permissions are, the larger the attack surface as well as greater likelihood of bugs.

iamruinous commented 8 years ago

Virtual Devices are shadows of a "real" device. A user can have discover/configure rights to a "shadow", and never even know that the real device exists. Using Meshblu Config Forwarding it becomes easy to forward all changes the user makes to a service that can then verify the update. To the user they are manipulating a Meshblu device just like any other.

We are currently building something similar to this to allow group device management in Octoblu. Below is a rough, untested example to convey the basic idea.

Given these Meshblu devices:

Admin = {
  uuid: "admin-uuid"
}

User = {
  uuid: "user-uuid"
}

Device = {
  uuid: "device-uuid",
  configureWhitelist: ["admin-uuid"],
  discoverWhitelist: ["admin-uuid"],
  meshblu: {
    configHooks: [
      {
        url:"http://device-service/original-update/device-uuid",
        method: "POST"
      }
    ]
  }
}

VirtualDevice = {
  uuid: "virtual-device-uuid",
  parentDevice: "device-uuid",
  configureWhitelist: [
    "user-uuid",
    "device-uuid"
  ],
  discoverWhitelist: [
    "user-uuid",
    "device-uuid"
  ],
  meshblu: {
    configHooks: [
      {
        url:"http://device-service/virtual-update/virtual-device-uuid",
        method: "POST"
      }
    ]
  }
}

The configHook specified in the VirtualDevice will forward the config event to any HTTP webhook.

// example express request handler, (untested psuedo-ish code)

var _ = require('lodash');
var MeshbluHttp = require('meshblu-http');
var OMITTED_FIELDS = ['uuid', 'meshblu', 'owner', 'token', 'sendWhitelist', 'receiveWhitelist', 'configureWhitelist', 'discoverWhitelist', 'sendBlacklist', 'receiveBlacklist', 'configureBlacklist', 'discoverBlacklist', 'sendAsWhitelist', 'receiveAsWhitelist', 'configureAsWhitelist', 'discoverAsWhitelist'];

function virtualUpdate(req, res) {
  var meshbluConfig = {uuid: 'device-uuid', token: 'device-token'};
  var meshbluHttp = new MeshbluHttp(meshbluConfig);
  var id = req.params.id;
  var update = _.omit(req.body, OMITTED_FIELDS);
  meshbluHttp.update(id, update, function(error) {
    if (error != null) {
      res.status(422).send(error.message);
    }
    return res.status(204).end();
  });
}

function deviceUpdate(req, res) {
  var meshbluConfig = {uuid: 'device-uuid', token: 'device-token'};
  var meshbluHttp = new MeshbluHttp(meshbluConfig);
  var id = req.params.id;
  var update = _.omit(req.body, OMITTED_FIELDS);
  meshbluHttp.find({parentDevice: id}, function(error, devices){
    _.each(devices, function(device){
      meshbluHttp.update(device.uuid, update, function(error) {
        ...
      });
    })
  });
}