SmartApp Web service permission model

I’m reading how a SmartApp is exposed as a web service and how the user must grant permission to the external entity that wants to communicate with the services offered by the SmartApp
(http://docs.smartthings.com/en/latest/smartapp-web-services-developers-guide/overview.html#authentication-authorization)

the doc says that the smartapp executes in a “special security context” where only authorized actions are allowed to happen. Presumably, this set of authorized actions comes directly from the user interacting with the UI.

  1. What happens when there are 2 different external entities that are using the same smartapp webservice but the user authorizes different permissions for each? Are there multiple copies of the smart app executing in different security contexts?

  2. My second question is whether such a screen that enables user to authorize what a smartapp can do is presented during installation of a regular smartapp? For example, suppose a SmartApp asks for ability to talk to device X, Y and Z. Is there is a screen for a regular smartapp that lets the user decide that the app only can talk to X and Y but not Z or is it that the app gets permission to access everything it asks for (a la android)

1 Like

I am going out on a limb here, but I want to see if someone corrects me if I’m wrong…

Firstly… Yes… The Preferences screen (whether in the mobile App or presented during web authentication) is the “only” way that a SmartApp gets authorized to individual Device Instances (or Lists of Devices of the same Capability), and stored in settings Map variable of scope to the SmartApp instances.

Multiple instances of the same SmartApp each have their own storage for state and settings, so can’t directly “steal” it from any other SmartApp or SmartApp instance.

I’m not certain that the authorized Devices are “secured”, however. Access is via the Device Object Instances… But are those possibly accessible by unhashed global account level device.id or some other reference?

The former case would be really bad and unlikely and easy to verify. Device.id alone would be a weak key / object reference.

The second case is slightly more likely to be a problem because a SmartApp could copy the Device reference (not just Device.id) into its own state map and possibly share or pass it around, even if the user subsequently de-authorizes (“un-checks”) a Device Instance by updating the Preferences in an existing installed SmartApp.


I’m almost embarrassed at how speculative the above description is; let’s say it is firmly only an untested, and certainly unproven, theory that I hope is easily, but thoroughly, disproven.

When you authorize an oAuth endpoint, you get a unique access url which includes just the access rights for that instance.

The SmartApp itself has full access to any devices you’ve authorized, by device id - if you grant access to a “switch” device that is also a dimmer, the smartapp can also use the dimming function - or if you grant access to any actuator (a fairly generic capability) which is also a lock, then the app can lock/unlock it, etc.

The device ids are identical to those shown in the IDE. Simply knowing a device ID is not sufficient to access the device from an oAuth endpoint or any smart app, for that matter, however. If you do that, you get back:

{"error":true,"type":"SmartAppException","message":"Device not found"}

So although the device id is a universal key, device visibility is on a per-authorized instance of the smart app.

At least that’s the way it seems from the outside.

2 Likes

I’m not sure I totally understand. Sure, you get an OAuth token that gives you some rights on the endpoint, but since the EndPoint is a SmartApp, the rights of the token must be the same as the rights of the SmartApp itself. That is, if the token says, you may only access device X and Y, then the SmartApp itself should only be able to access X and Y, otherwise, if the SmartApp can also access some device Z, that opens potential for a badly written SmartApp to be exploited so that the external entity can access device Z even though the user only authorized X and Y.

If this is true, then if there are 2 consumers of the SmartApp web service, there must necessarily be 2 instances of the same SmartApp, otherwise you get permission bloat. If there are multiple instances of the same SmartApp, that becomes very confusing. Suppose, I have a light controller and suppose there are 2 instances. The light could get conflicting messages and I will have no way to reconciling them.

There is a single instance for each endpoint/oauth token. That instance has whatever the user allowed for access via the smart app (just like when you install a smart app, and select which devices it can use in any other case.) The use case (and likely implementation) are pretty much exactly the same.

The device itself can get messages from as many apps as you like, and it does whatever it does. If I have three apps all turning the light on or off based on different, even conflicting rules, it will just process the commands as they come in.

Yes, it is possible to have two apps turning a light on, then off, then on, then off… it’s quite funny.

2 Likes

Yep. So if you install a battery monitor app and only select the battery portion of your lock the the smart app can lock and unlock your door.

I think an elegant solution would be a read-only grant. For example, the end user selects their devices and clicks save. A dialog should pop up telling the user what permissions the smart app is going to ask for and the give the user the option to grant full or read-only access to the smartapp. It’s not bulletproof. I would prefer that granting access to your locks battery be explicit and only allow access to the battery. I think each capability should be treated as an individual entity.

1 Like

That is a reasonable wish-list item (i.e., improved authorization granularity down to, well, Capability if the Capability taxonomy were keeping up with new Device Types … So without that, granularity needs to be down to Attribute and Command level, ideally, but tough for users to understand). RO vs. RW is a compromise.

But can’t hold breath. So I’m just curious if the currently spec’d model is working properly with no exploitable vulneralbilities.

A way to get read/write granularity is to expose multiple capabilities from a single device, if that’s possible.

1 Like

Yes, there are multiple capabilities from each device type, and that is the method of obtaining this sort of granularity. In fact, you can create custom device types with additional capabilities not “native” to the device. This can be useful for mapping odd devices into familiar ones so the device can be accessed by SmartApps that don’t know about the device in a native sense. And on it goes from there…

But, I don’t think there is any mechanism that prevents a SmartApp from accessing any of the capabilities of the devices it deals with. It can find out it’s capabilities. For example, a SmartApp that selects a switch, can discover that in fact the switch is a dimmer, and then it can dim it. So the selection of capability.switch does not restrict the SmartApp to only the commands available for a switch, if the selected device is a dimmer, or anything else for that matter.

1 Like

but if there are 2 different capabilities exposed by a single device, the smartapp will have to explicitly ask for both those capabilities right? And the user might allow cap1 but disallow cap2

No. The SmartApp device selection works based on the capability specified in the Preferences section of the app. The user is presented a list of devices that possess that capability, and the user selects the devices she wants the SmartApp to use. Once selected, there is nothing that prevents the SmartApp from accessing all of the commands that the device in question offers. Those commands might reference capabilities beyond the one used to cause the device selection list offered to the user.

Oh I see! For example, suppose there is some device X with capabilities cap1 and cap2. Further assume that a SmartApp wants cap1, so it will declare that in the preferences section. Then the installer UI will enumerate all devices supporting cap1, including devices that support additional capabilities. In this example, device X will be listed. The moment the smartapp is authorized to access cap1, it can just as easily access cap2.

Assuming I understood correctly, this means you cannot implement read/write granulrity capabilities securely.

That is 100% correct.

Another way to put it: The input clauses in SmartApp Preferences are the only way to allow the user to specify which Devices each SmartApp can access, but that is the finest level of granularity.

The “capability.<name>” filter is just to:

  1. Filter the list for user convenience.
    and
  2. Conveniently group the resulting Devices into one List variable so that the SmartApp developer can expect all of the Devices to serve the contract specified by the Capability (i.e., Every Device in the Switch List variable has Attribute switch [on/off] and Commands on()/off()).

That’s not perfect, but it’s not bad out of the gate and it will be a long time before SmartThings ever changes it. Heck, SmartThings doesn’t even comment on the several good new Capabilities we’ve requested for discussion! Adding access security granularity is a major upgrade.

At one point the Documentation implied we could “declare” new Capabilities on the fly (e.g., “Capability ThreePositionSwitch”) so that ad hoc Attributes and Commands would at least be grouped for later reference. But nope. Doc error.


But I remind everyone that I’m not 100% convinced the existing security model is implemented as spec’d. But i guess I should “put up or shut up” … i.e., no use voicing my theory without testing and proving. But IF we discover and expose proof, who does that hurt or help? ST is unlikely to fix it very quickly, and then “we” would have published an vulnerability which could be exploited by bad guys… :confused:

Well, yes, that’s true. So if the user installs a web service SmartApp that she then gives access to certain devices to, then that user is implicitly granting full access to those devices to that SmartApp, and by extension, to who knows what. But, for now at least, we operate mostly in a source code exposed environment, or with “trusted” apps from ST.

1 Like

I should point out that there are ways to get to this granularity using custom device types. For example, I could create a new device type for a switch that offers on() but not off(). That device type would still have capability.switch, so it would show up in the list of devices the user selects when installing the SmartApp. That device offers the read-only security you are talking about. The SmartApp could not get device.off() to work, even though the underlying physical device is a switch.

2 Likes

Not a bad idea, except difficult to manage because SmartThings doesn’t provide any easy way to associate multiple “Things” (Device Instances) with one physical Device.

The straightforward implementation would be to add one or more Virtual Switches, each with different pared-down set of Attributes and Commands to your heart’s desire, but there would be no way to filter in the Preferences input (Device List filtering is really weak … You can specify a single Capability only, there is no “and / or / regular expressions”).

The trouble might be worth it for something like a Lock: You want a Device Instance that gives read-only access to the state of “locked/unlocked” to make it look like a Contact Sensor (heck, call the states “closed/open”), and a second Device Instance that actually has Commands. The first Device Instance you can grant to your Echo or Ubi so that it can be asked “Is my front door locked?”, but the Echo or Ubi will not be able to ever to “accidentally” act on the utterance “Unlock the front door.”.

do some pen-testing :smile:
I’m doing some of my own anyway.

1 Like