Luup Secure Plugins
Luup Secure Plugins
Contents |
Changes and advantages
This document introduces a few new concepts that are new to the 1.2.xxx releases with UI4. Although the document is long, the process is actually streamlined and simpler, the document just tries to explain all use cases. Now you just call locator.php (or locator_json.php) and get back the list of servers and all MiOS engines in one call, and then you call the CreateDevice or CreatePlugin action, and from then on you're ready to just like with UI2/UI3. The goal is also to address all possible use cases for future applications, including tightly integrated media control when the MiOS engine is embedded into media devices like TV's, so that the API can be frozen for a long time without needing to make changes to accommodate future functionality.
1. Security -- One of the big problems with UI2/3 was that anybody on the local network could control any device, including unlocking doors. Now you will pass the username/password with all your requests to prevent unauthorized access. So, if you have a cell phone app, you will prompt the user for his username/password and append them to all requests.
2. Local https -- To protect the username/password, when you make a request on the local network you can use https instead of http. If whatever you're using to make the requests doesn't support https then you can still use http but you should *never* pass the username/password this way. For example, maybe you have a cell phone app that can only do http requests, not https. In this case, you can ask the user for his username but not his password. The mios engine will still work but may refuse to execute certain actions that are considered "high security" like unlocking doors and disarming alarms.
3. Unified username/password -- With UI2/UI3 people created a username for remote access, and separately created users for local access. This created a lot of confusion. Now it's unified usernames/passwords that are synced.
4. Many-to-many access -- With UI2/UI3 a given remote access username could only access one engine. Now it's many to many. So 3 family member can access the "New York Home", and Dad can also access the "Florida Home". Now when you call locator.php or locator_json.php you just pass in the username and get back a list of all the engines that user can control, both locally and remotely.
5. Redundant servers -- With UI2/UI3 if the remote access server went down you lost access. Now there's a backup server for each engine that is used if the main one goes down.
6. Device numbers for all cell phones -- With UI2/UI3 the cell phones that controlled the engine weren't identified. Now each cell phone gets a unique device number. This allows us to add restrictions in the engine, for example, the maid's cell phone cannot be used to change lock codes. And it also allows the cell phones to receive messages, not just send them, which opens up lots of possibilities particularly if the cell phone can run the app in the background. For example, a 'locate my phone' scene can be attached to an in wall controller that makes the phone beep. Or a tablet can be put on the wall and paired with a media playback device so it automatically displays cover art and navigation controls for whatever media is going on in that room. When you're cell phone polls the engine with lu_status, a new tag in lu_status will include incoming messages your device.
Overview
MiOS has a secure way of provisioning plugins, which will generally be done for non-free applications. This mechanism can be used equally well for paid-for external apps that communicate with Vera, like a cell phone control, by creating an associated plugin for the app, even if the plugin doesn't do anything. The process of creating the plugin is no different than normal.
Let's say you have a free cell phone app with no restrictions. You still use the same mechanism. Just ask Mios for a plugin ID that is free and unrestricted. It will be empty plugin that does nothing. When you provision your phone, use that plugin in. Provisioning external 3rd party apps, like cell phone controls, is not just for copy protection and financial, it's also done to give the home owner control over what devices are taking control of his system and having a way of restricting that if he wants to. If you try to communicate with a MiOS engine over a local network without being provisioned, you can still do a lot, but certain secure actions, like unlocking doors and disarming alarms won't be processed by the engine if your app isn't provisioned to prevent a security risk.
A provisioned plugin contains 3 fields of data: 'from' and 'to' which are date/time's, and 'limits' which is a free form text field that can be used by the plugin or external app to determine what functionality can be provided. These 3 fields exist both for the plugin itself, and for devices that use the plugin. When registering your app with MiOS you specify what the default values are if a user first installs your plugin without paying for anything. For example, consider that you have a plugin that monitors traffic conditions and costs $3/year to monitor local traffic and $6/year to monitor nation traffic and each homeowner has a 14 day free trial of the plugin, and that the limit code for the trial period is "trial" and for the $3 app is "local" and for the $6 app is "national" or $20 for national lifetime. You would specify with your MiOS Market representative that the default time period is 14 days and the default limit code is "trial". When the user installs the app, the plugin will have provision data where 'from' is the date he installed the plugin, 'to' is 14 days later, and 'limit' is "trial". When the customer pays the $3 or $6 the 'to' field will change to 1 year and the 'limit' will change also, when he pays $20, the 'to' field will become empty.
Some plugins create devices which may require provisioning of each device in addition to or instead of the provisioning for the main plugin. For example, a cell phone app may have a price of $10 for the first cell phone and $2 for each additional one. In this case, unlike the traffic example which only created a plugin entry, a device entry will be created for each phone and provision from/to/limit fields will exist for each phone as well as each device. Again, there could be a free trial period which uses the 'limit' code, and the first phone could use the 'included' code, and the subsequent phones could have 'extra' limit code. The limit codes are entirely free-form and it's up to you to decide what they mean.
The provisioning process itself is done by automated systems, contact MiOS to setup an account for payment and establish the terms of provisioning.
To retrieve the provisioning status of your plugin request the provisioning info as an lu request, like: http://ip:3480/data_request?id=lu_provision&PluginNum=x&DeviceNum=y. Note DeviceNum is optional, and whether specified or not, you'll receive in json format the all the provisioning info for the plugin and any associated devices. If DeviceNum is specified the encryption key for the device will be used to encrypt the return value, rather than using the key for the plugin itself. Encryption is optional (see section below). The format of lu_provision is:
{ "AllowMultiple": 1, "Title": "Test Secure Plugin", "timestamp": 1270155180, "Provision": { "from": 1270155180, "to": 1272697200, "limits": "trial", "Devices": [ { "from": 1272697200, "to": 1272783600, "limits": "trial", "device_num": "2", "altid": "2135551212" }, { "limits": "", "device_num": "8", "altid": "3105001000" } ] }, "Version": "0.50", "id": 144, }
Note this means the plugin itself has a provision from 1270155180 to 1272697200 (unix timestamp) with limit "trial", and the 2 devices which are associated with the plugin have their own provision data.
A plugin is an app that contains code. A device is something that a user interacts with, or which sends actions, generates events. Some plugins logically have device(s) associated with them, others don't. For example, there may be a plugin that monitors traffic. This doesn't have any devices that the user interacts with; it's just a plugin and will be created with CreatePlugin as shown in the next sample. However if your plugin interfaces with some device, for example, a mobile phone control, or an alarm, etc., then you'll have the plugin itself which optionally contains any Luup code you may have written, and additionally there will be device(s) which the plugin handles. The engine will automatically assign each device a unique number, and you can also give each device an alphanumeric id to identify the device (called the 'altid'), as well as a free form description which is what the user sees.
One simple example is let's say you have a cell phone control app. MiOS will give you a unique plugin id for your app, say it's 281. You will call CreateDevice as shown below, passing in your plugin id, and the engine will create a device that represents your phone. The altid for your phone may be the phone number: 2125551212 and the description may be: "John's iPhone". Now if John's wife, Mary, installs your app on her phone, her phone will also CreateDevice passing in a different altid, which causes the engine to create a 2nd device that is associated with your plugin.
Step by step process of provisioning an external app like a mobile phone
Plugins which are done in Luup are automatically handled by the MIOS engine and the user interface. Here is a step-by-step example showing how you might handle setup of a mobile phone app. This is just a sample showing one possible implementation. Note the Aeskey arguments in these samples are optional and explained in the next section.
1. Ask the user for his myMiOS username. Let's say it's "john" and then call http://sta1.mios.com/locator.php?username=john and if you don't get a reply because the server or network is down, try the backup server: http://sta2.mios.com/locator.php?username=john and if you want the same data to be formatted in a structured json output, use locator_json.php instead.
This will return a list of all the MiOS engines which you can control, both those which are on the local network that you can control directly, and those that the user "john" can control through the mios.com portal. The return value is a list of serial numbers, internal IP addresses, user names, main port forward server, backup port forward server, as follows:
10998,192.168.2.10,alfonso,fwd2.mios.com,fwd1.mios.com 11020,,john,fwd2.mios.com,fwd1.mios.com 10266,192.168.2.117,,, 10267,192.168.2.119,john,fwd2.mios.com,fwd1.mios.com 10267,192.168.2.119,alfonso,fwd2.mios.com,fwd1.mios.com
This means you can control 4 MiOS engines. 10998, 10266 and 10267 are on the local network as evidenced by Internal IP not being blank. 10998 you can control either locally at 192.168.2.10 or through the mios portal with the user 'alfonso'. Note that the user you passed in 'john' cannot control 10998 through the mios portal, but it's shown to you anyway since it's on the same local network as your phone. 11020 is not on your local network, so the IP is blank, but john can control it through the forward servers. 10266 can only be controlled locally with no remote access. 10267 is one john can control either locally or remotely. Since it's on the local network and alfonso is another username that can control it remotely, you are shown it too.
So all your control options are available with locator.php. How you want to present this to the user is up to the developer, but, presumably you could just show the user all 5 rows and let him pick the one he wants. You can leave the username=x off the URL, and in this case the return list will only include those engines on the local network.
Your app should now prompt the user for the password if there is a username associated. For example, 10266 will allow you to provision an app without a username/password since the user, during setup, explicitly decided to bypass the default security settings in the wizard which create a username/password, and he chose to have an unsecure system. The 10266 example is a rare exception since a user who does this is exposing himself to risk in case someone gets on his local area network they can control his door locks, etc. So, generally, users will follow the setup wizard's advice and protect their box with a username/password. This is the only case in which the commands to create a plugin will actually work without a username/password, otherwise they'll return a 'not authorized' error.
Assume you've got a cell phone app that talks to the engine over wi-fi and the homeowner doesn't have internet access. In this case you can discover the engine by doing a upnp scan or asking the user to enter the IP of the engine. He still probably protected his engine with a username/password so you should still prompt him for this, but, allow him to continue with an empty user/pass just in case he did create a wide open system like 10266.
2a. Assuming that your going to track individual phones, you'll want to create a device for this phone. So you'll need to come up with a unique ID for the phone. It can be whatever the phone provides, such as a mac address, phone number, etc., or, if the phone doesn't provide anything, generate a unique id on your own, perhaps a timestamp, which you should try to install in some persistent memory on the phone so that if your app is uninstalled and reinstalled it will retain the same ID and not get provisioned twice. The id must have normal characters only: A-Z a-z 0-9 space - _ : and to ensure it does not conflict with the ID of another developer's device, preface it with some unique characters for your app, like: ACME_PHONE_CO_2135551212. Then, to create the device, call:
for a remote IP over the portal you have to ask the user for his password and call: https://[fwd_server]/username/password/serial_number/data_request?id=lu_action&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=CreateDevice&deviceType=anytype&internalID=ACME_PHONE_CO_2135551212&Description=phoneapp&PluginNum=144&Reload=1&NoDupId=1&AesKey=abc123&username=john&password=johnspassword
Note that the URL is exactly the same whether communicating locally or remotely, only the first part changes. This also means that if you're communicating remotely, the username/password will get passed on the URL twice; once in the first set of /'s, which is validated by the portal, and also in the URL which is validated by the engine.
Note that you have 2 forward servers. The engine will only keep one connection active at a time, and will try to always keep the connection active to the first server and will revert to the second server only if the first one is down, and, if that happens, it will go back to the first server as soon as it comes alive again. So always use the first server and only try the second one if the first fails. If you're using the second server and it fails at any time, go back to the first one.
Note the deviceType is a UPnP device type, and you can simply make one up for your device however you should use the standard upnp naming convention for clarity, like: urn:schemas-acmephone-com:device:AndroidApp:1. The PluginNum is the id of the plugin which you created in the MiOS market, Reload=1 means the MiOS engine will reload after creating the device so it gets initialized, NoDup=1 means that if there's already a device with the ID ACME_PHONE_CO_2135551212 then CreateDevice will return the existing device id rather than create a new one. AesKey can be a Aes128 or Aes256 key which you generate at random and that you want the MiOS engine to use to encrypt communication with you to prevent man in the middle hacks to fake provisioning. If submitting an AesKey, you should use https:// to send this to the MiOS engine, which will store it in an encrypted state. There is no way to retrieve the AesKey again however you can change it by calling CreateDevice again with the same internalID, NoDup=1 and a new key. See the section on security below. This request will return the device id of the newly created device. When the MiOS engine reloads it will download the plugin information and the provision data, like this: http://download1.mios.com/get_plugin_json.php?plugin=144&ap=10266 (ap is the serial number). This will have the default provisioning for now. An icon will appear in the toolbox that allows the user to purchase and configure the plugin. You can also make the request using the myMiOS server.
Note that for many of these devices, like phones, you might not want them to appear on the user's dashboard, particularly if there's no buttons or settings for the device that you want the user to set in the UI. In such a case append &invisible=1 to the URL for CreateDevice so it doesn't show up as a device in the UI.
Remember that the device ID is unique to each MiOS system, and multiple systems can be controlled with the same myMiOS username. So you will need to create a device on each MiOS system you want to control and keep track of which device ID belongs to which system.
2b. If you did not want to get a device id for the phone, and just want to provision the plugin for this MiOS engine, meaning only the plugin is provisioned and you won't be tracking devices, then just use CreatePlugin instead of CreateDevice: http[s]://...../data_request?id=lu_action&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=CreatePlugin&PluginNum=144&AesKey=abc123&username=john&password=johnspassword.
3. Wait until the engine finishing reloading and downloading the plugin and then you'll see a Provision tag in the user_data for your device with the provision codes. You can also retrieve the provision data by itself with /data_request?id=lu_provision&PluginNum=yyy&DeviceNum=xxx where DeviceNum is optional and only used if you created a device ID for your phone. user_data will contain the timestamp for the plugin which will show when the plugin data last changed so you know when to retrieve lu_provision again if the plugin provisioning has changed.
Refreshing the provision data
If the plugin was provisioned, but the new provision data is not in Vera, you can call CreatePlugin again with the plugin number. Do not worry about creating 2 instances of the plugin. You can call CreatePlugin as often as you want to refresh the data.
Copy protection
To prevent users from circumventing the provisioning process the MiOS engine retrieves the plugin data using https and verifies the public key of the mios server. Additionally if you want to prevent a man in the middle attack where the user tries to circumvent your provision process, you can optionally supply an AesKey which means that lu_provision will always return the provision data encrypted with your key to provide you assurance you're talking to the real MiOS engine. This is the AesKey argument on the CreateDevice and CreatePlugin examples, and is optional.